mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-20 13:57:43 +00:00
Compare commits
37 Commits
dev/duhowe
...
v1.24.3504
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6115cf31f5 | ||
|
|
b277e4b515 | ||
|
|
8a8d02f7e1 | ||
|
|
1ba28b298f | ||
|
|
ba6cd3ebd5 | ||
|
|
5c543bb2be | ||
|
|
8b07837fdd | ||
|
|
4fd7751d83 | ||
|
|
47da5a11b2 | ||
|
|
08a981d7b7 | ||
|
|
7e69a2e96f | ||
|
|
5205575d4d | ||
|
|
7a34181fc7 | ||
|
|
b38489b67b | ||
|
|
d25b84d4c1 | ||
|
|
9ab1b7ba3b | ||
|
|
d35bc4cee6 | ||
|
|
77ee52b872 | ||
|
|
671552671d | ||
|
|
58a5088735 | ||
|
|
c5f99b69d5 | ||
|
|
6f5b293a56 | ||
|
|
e33bc3d137 | ||
|
|
6aae2d0b72 | ||
|
|
148a86c81c | ||
|
|
94e96ca048 | ||
|
|
b53d7df066 | ||
|
|
1194ad0343 | ||
|
|
04e1290102 | ||
|
|
f5083714c1 | ||
|
|
7642eec206 | ||
|
|
37c674dd6e | ||
|
|
3a57ba54a0 | ||
|
|
fc465bdae6 | ||
|
|
04a5dffdcd | ||
|
|
894e57769b | ||
|
|
eb206177a4 |
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
@@ -178,6 +178,7 @@ ubrk
|
||||
UChar
|
||||
UFIELD
|
||||
ULARGE
|
||||
UNCEx
|
||||
UOI
|
||||
UPDATEINIFILE
|
||||
urlmon
|
||||
|
||||
7
.github/actions/spelling/expect/expect.txt
vendored
7
.github/actions/spelling/expect/expect.txt
vendored
@@ -1091,6 +1091,8 @@ NEXTLINE
|
||||
nfe
|
||||
NLSMODE
|
||||
NOACTIVATE
|
||||
NOACTIVATEKEYBOARDLAYOUT
|
||||
NOACTIVATETIP
|
||||
NOAPPLYNOW
|
||||
NOCLIP
|
||||
NOCOMM
|
||||
@@ -1505,7 +1507,6 @@ scrolllock
|
||||
scrolloffset
|
||||
SCROLLSCALE
|
||||
SCROLLSCREENBUFFER
|
||||
scursor
|
||||
sddl
|
||||
SDKDDK
|
||||
segfault
|
||||
@@ -1703,9 +1704,11 @@ TEXTMETRIC
|
||||
TEXTMETRICW
|
||||
textmode
|
||||
texttests
|
||||
TFCAT
|
||||
THUMBPOSITION
|
||||
THUMBTRACK
|
||||
tilunittests
|
||||
TIPCAP
|
||||
titlebars
|
||||
TITLEISLINKNAME
|
||||
TLDP
|
||||
@@ -1757,6 +1760,8 @@ UIACCESS
|
||||
uiacore
|
||||
uiautomationcore
|
||||
uielem
|
||||
UIELEMENTENABLED
|
||||
UIELEMENTENABLEDONLY
|
||||
UINTs
|
||||
uld
|
||||
uldash
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"DisableAutoPackageNameFormatting": false
|
||||
},
|
||||
"appSubmission": {
|
||||
"appId": "9N8G5RFZ9XK3",
|
||||
"productId": "00014050269303149694",
|
||||
"targetPublishMode": "NotSet",
|
||||
"targetPublishDate": null,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"DisableAutoPackageNameFormatting": false
|
||||
},
|
||||
"appSubmission": {
|
||||
"appId": "9N0DX20HK701",
|
||||
"productId": "00013926773940052066",
|
||||
"targetPublishMode": "NotSet",
|
||||
"targetPublishDate": null,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"collection": "microsoft",
|
||||
"project": "OS",
|
||||
"repo": "os.2020",
|
||||
"name": "official/rs_we_adept_e4d2",
|
||||
"name": "official/ge_current_directwinpd_deep",
|
||||
"workitem": "38106206",
|
||||
"CheckinFiles": [
|
||||
{
|
||||
|
||||
@@ -53,8 +53,12 @@ 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 VPack to Windows"
|
||||
displayName: "Publish above VPack to Windows"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
@@ -89,6 +93,7 @@ extends:
|
||||
clientId: $(SigningOriginalClientId)
|
||||
terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }}
|
||||
publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }}
|
||||
createVpack: ${{ parameters.createVpack }}
|
||||
publishVpackToWindows: ${{ parameters.publishVpackToWindows }}
|
||||
symbolPublishingSubscription: $(SymbolPublishingServiceConnection)
|
||||
symbolPublishingProject: $(SymbolPublishingProject)
|
||||
|
||||
@@ -49,6 +49,9 @@ 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
|
||||
@@ -192,8 +195,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.publishVpackToWindows) }}
|
||||
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.publishVpackToWindows) }}
|
||||
ob_createvpack_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack) }}
|
||||
ob_updateOSManifest_enabled: ${{ and(parameters.buildTerminal, parameters.createVpack, parameters.publishVpackToWindows) }}
|
||||
### If enabled above, these options are in play.
|
||||
ob_createvpack_packagename: 'WindowsTerminal.app'
|
||||
ob_createvpack_owneralias: 'conhost@microsoft.com'
|
||||
@@ -229,7 +232,7 @@ extends:
|
||||
New-Item "$(JobOutputDirectory)/vpack" -Type Directory
|
||||
displayName: Make sure the vpack directory exists
|
||||
|
||||
- ${{ if parameters.publishVpackToWindows }}:
|
||||
- ${{ if parameters.createVpack }}:
|
||||
- pwsh: |-
|
||||
Copy-Item -Verbose -Path "$(MsixBundlePath)" -Destination (Join-Path "$(JobOutputDirectory)/vpack" 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle')
|
||||
displayName: Stage msixbundle for vpack
|
||||
|
||||
@@ -2302,8 +2302,15 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The ID of the command this keybinding should execute.",
|
||||
"type": "string"
|
||||
"description": "The ID of the command this keybinding should execute (or null to disable a default).",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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",
|
||||
@@ -2459,6 +2466,7 @@
|
||||
"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"
|
||||
]
|
||||
@@ -2472,8 +2480,9 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.input.forceVT": {
|
||||
"description": "Force the terminal to use the legacy input encoding. Certain keys in some applications may stop working when enabling this setting.",
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"description": "[Deprecated] Replaced with the \"compatibility.input.forceVT\" profile setting.",
|
||||
"deprecated": true
|
||||
},
|
||||
"experimental.useBackgroundImageForWindow": {
|
||||
"default": false,
|
||||
@@ -2520,14 +2529,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": {
|
||||
@@ -2573,9 +2582,12 @@
|
||||
"$ref": "#/$defs/NewTabMenu"
|
||||
},
|
||||
"language": {
|
||||
"default": "",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"description": "Sets an override for the app's preferred language, expressed as a BCP-47 language tag like en-US.",
|
||||
"type": "string"
|
||||
"default": null
|
||||
},
|
||||
"theme": {
|
||||
"default": "dark",
|
||||
@@ -2639,19 +2651,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
|
||||
@@ -2708,12 +2720,12 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"acrylicOpacity": {
|
||||
"type": "number",
|
||||
"description": "[Deprecated] Replaced with the \"opacity\" setting.",
|
||||
"default": 0.5,
|
||||
"description": "[deprecated] Please use `opacity` instead.",
|
||||
"deprecated": true,
|
||||
"maximum": 1,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
"maximum": 1,
|
||||
"deprecated": true
|
||||
},
|
||||
"antialiasingMode": {
|
||||
"default": "grayscale",
|
||||
@@ -2739,6 +2751,11 @@
|
||||
"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.",
|
||||
@@ -2910,24 +2927,29 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.autoMarkPrompts": {
|
||||
"deprecated": true,
|
||||
"description": "This has been replaced by autoMarkPrompts in 1.21",
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"description": "[Deprecated] Replaced with the \"autoMarkPrompts\" setting.",
|
||||
"deprecated": true
|
||||
},
|
||||
"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": {
|
||||
"deprecated": true,
|
||||
"description": "This has been replaced by showMarksOnScrollbar in 1.21",
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"description": "[Deprecated] Replaced with the \"showMarksOnScrollbar\" setting.",
|
||||
"deprecated": true
|
||||
},
|
||||
"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.",
|
||||
@@ -2943,23 +2965,29 @@
|
||||
"type": "string"
|
||||
},
|
||||
"fontFace": {
|
||||
"default": "Cascadia Mono",
|
||||
"description": "[deprecated] Define 'face' within the 'font' object instead.",
|
||||
"type": "string",
|
||||
"description": "[Deprecated] Replaced with the \"face\" setting within the \"font\" object.",
|
||||
"default": "Cascadia Mono",
|
||||
"deprecated": true
|
||||
},
|
||||
"fontSize": {
|
||||
"default": 12,
|
||||
"description": "[deprecated] Define 'size' within the 'font' object instead.",
|
||||
"minimum": 1,
|
||||
"type": "number",
|
||||
"description": "[Deprecated] Replaced with the \"size\" setting within the \"font\" object.",
|
||||
"default": 12,
|
||||
"minimum": 1,
|
||||
"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",
|
||||
@@ -2972,13 +3000,7 @@
|
||||
"extra-bold",
|
||||
"black",
|
||||
"extra-black"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"maximum": 990,
|
||||
"minimum": 100,
|
||||
"type": "integer"
|
||||
]
|
||||
}
|
||||
],
|
||||
"deprecated": true
|
||||
@@ -3089,7 +3111,10 @@
|
||||
},
|
||||
"answerbackMessage": {
|
||||
"description": "The response that is sent when an ENQ control character is received.",
|
||||
"type": "string"
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"description": "Stores the name of the profile generator that originated this profile.",
|
||||
|
||||
@@ -44,10 +44,6 @@ 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()
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
<value>Déplacer l'onglet vers une nouvelle fenêtre </value>
|
||||
</data>
|
||||
<data name="RunAsAdminFlyout.Text" xml:space="preserve">
|
||||
<value>Exécuter en temps qu'administrateur (restreint)</value>
|
||||
<value>Exécuter en tant 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">
|
||||
|
||||
@@ -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>
|
||||
@@ -317,7 +317,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 +345,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 +365,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 +381,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 +412,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 +429,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 +439,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 +857,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 +872,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 +892,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 +908,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 +930,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 +961,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>
|
||||
|
||||
@@ -1062,7 +1062,6 @@ namespace winrt::TerminalApp::implementation
|
||||
dispatcher,
|
||||
til::throttled_func_options{
|
||||
.delay = std::chrono::milliseconds{ 200 },
|
||||
.leading = true,
|
||||
.trailing = true,
|
||||
},
|
||||
[weakThis]() {
|
||||
@@ -2418,7 +2417,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto& currentDictionary = v.as<ResourceDictionary>();
|
||||
|
||||
// TabViewItem.Background
|
||||
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush);
|
||||
currentDictionary.Insert(winrt::box_value(L"TabViewItemHeaderBackground"), selectedTabBrush);
|
||||
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);
|
||||
|
||||
@@ -157,12 +157,7 @@ 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*/) {
|
||||
@@ -664,7 +659,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 Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept
|
||||
winrt::TerminalApp::Tab TerminalPage::_GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept
|
||||
{
|
||||
uint32_t tabIndexFromControl{};
|
||||
const auto items{ _tabView.TabItems() };
|
||||
@@ -876,60 +871,64 @@ namespace winrt::TerminalApp::implementation
|
||||
_UpdateTabView();
|
||||
}
|
||||
|
||||
// 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)
|
||||
void TerminalPage::_OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e)
|
||||
{
|
||||
if (eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
|
||||
if (!_tabItemMiddleClickHookEnabled || !e.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
|
||||
{
|
||||
if (const auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
{
|
||||
_tabPointerMiddleButtonPressed = tabViewItem.CapturePointer(eventArgs.Pointer());
|
||||
_tabPointerMiddleButtonExited = false;
|
||||
}
|
||||
eventArgs.Handled(true);
|
||||
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())
|
||||
{
|
||||
_OnTabPointerReleasedCloseTab(std::move(sender));
|
||||
}
|
||||
|
||||
e.Handled(true);
|
||||
});
|
||||
e.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::_OnTabPointerReleased(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
|
||||
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(IInspectable sender)
|
||||
{
|
||||
if (_tabPointerMiddleButtonPressed && !eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
|
||||
{
|
||||
_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());
|
||||
|
||||
const auto tab = _GetTabByTabViewItem(sender);
|
||||
if (!tab)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// `tab.Shutdown()` in `_RemoveTab()` sets the content to null = This checks if the tab is closed.
|
||||
if (tab.Content())
|
||||
{
|
||||
@@ -937,34 +936,6 @@ 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.
|
||||
|
||||
@@ -60,8 +60,42 @@ namespace winrt
|
||||
|
||||
namespace clipboard
|
||||
{
|
||||
wil::unique_close_clipboard_call open(HWND hwnd)
|
||||
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.
|
||||
@@ -80,7 +114,12 @@ namespace clipboard
|
||||
Sleep(sleep);
|
||||
}
|
||||
|
||||
return wil::unique_close_clipboard_call{ success };
|
||||
if (!success)
|
||||
{
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
}
|
||||
|
||||
return ClipboardHandle{ success };
|
||||
}
|
||||
|
||||
void write(wil::zwstring_view text, std::string_view html, std::string_view rtf)
|
||||
@@ -344,6 +383,8 @@ 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:
|
||||
@@ -3175,33 +3216,17 @@ 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
const auto result = co_await catalog.FindPackagesAsync(options);
|
||||
const IVectorView<MatchResult> pkgList = result.Matches();
|
||||
co_return pkgList;
|
||||
}
|
||||
|
||||
@@ -3808,6 +3833,8 @@ 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);
|
||||
|
||||
@@ -391,7 +391,7 @@ namespace winrt::TerminalApp::implementation
|
||||
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 Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) const noexcept;
|
||||
TerminalApp::Tab _GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept;
|
||||
|
||||
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
|
||||
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::Tab tab);
|
||||
@@ -435,13 +435,18 @@ namespace winrt::TerminalApp::implementation
|
||||
void _TabDragStarted(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
void _TabDragCompleted(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
|
||||
bool _tabPointerMiddleButtonPressed{ false };
|
||||
bool _tabPointerMiddleButtonExited{ false };
|
||||
// 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;
|
||||
void _OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
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);
|
||||
safe_void_coroutine _OnTabPointerReleasedCloseTab(IInspectable sender);
|
||||
|
||||
void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs);
|
||||
void _OnTabItemsChanged(const IInspectable& sender, const Windows::Foundation::Collections::IVectorChangedEventArgs& eventArgs);
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace winrt::TerminalApp::implementation
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(sounds.GetAt(rand() % sounds.Size()).c_str()) };
|
||||
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
|
||||
winrt::Windows::Foundation::Uri uri{ soundPath };
|
||||
_playBellSound(uri);
|
||||
}
|
||||
|
||||
@@ -1048,6 +1048,11 @@ 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;
|
||||
|
||||
@@ -149,12 +149,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
|
||||
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
|
||||
_renderer->SetRendererEnteredErrorStateCallback([this]() { RendererEnteredErrorState.raise(nullptr, nullptr); });
|
||||
_renderer->SetRendererEnteredErrorStateCallback([this]() { _rendererEnteredErrorState(); });
|
||||
}
|
||||
|
||||
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
|
||||
@@ -911,6 +926,7 @@ 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);
|
||||
@@ -1912,6 +1928,7 @@ 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -347,6 +347,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
safe_void_coroutine _renderEngineSwapChainChanged(const HANDLE handle);
|
||||
void _rendererBackgroundColorChanged();
|
||||
void _rendererTabColorChanged();
|
||||
void _rendererEnteredErrorState();
|
||||
#pragma endregion
|
||||
|
||||
void _raiseReadOnlyWarning();
|
||||
@@ -401,6 +402,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
float _panelWidth{ 0 };
|
||||
float _panelHeight{ 0 };
|
||||
float _compositionScale{ 0 };
|
||||
uint8_t _renderFailures{ 0 };
|
||||
|
||||
// Audio stuff.
|
||||
MidiAudio _midiAudio;
|
||||
|
||||
@@ -485,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 int32_t delta,
|
||||
const Core::Point delta,
|
||||
const Core::Point pixelPosition,
|
||||
const Control::MouseButtonState buttonState)
|
||||
{
|
||||
@@ -506,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,
|
||||
WM_MOUSEWHEEL,
|
||||
delta.Y != 0 ? WM_MOUSEWHEEL : WM_MOUSEHWHEEL,
|
||||
modifiers,
|
||||
::base::saturated_cast<short>(delta),
|
||||
::base::saturated_cast<short>(delta.Y != 0 ? delta.Y : delta.X),
|
||||
buttonState);
|
||||
}
|
||||
|
||||
@@ -517,15 +517,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
if (ctrlPressed && shiftPressed && _core->Settings().ScrollToChangeOpacity())
|
||||
{
|
||||
_mouseTransparencyHandler(delta);
|
||||
_mouseTransparencyHandler(delta.Y);
|
||||
}
|
||||
else if (ctrlPressed && !shiftPressed && _core->Settings().ScrollToZoom())
|
||||
{
|
||||
_mouseZoomHandler(delta);
|
||||
_mouseZoomHandler(delta.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
_mouseScrollHandler(delta, pixelPosition, WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown));
|
||||
_mouseScrollHandler(delta.Y, pixelPosition, WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -659,7 +659,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core->IsVtMouseModeEnabled();
|
||||
}
|
||||
|
||||
bool ControlInteractivity::_shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta)
|
||||
bool ControlInteractivity::_shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const Core::Point delta)
|
||||
{
|
||||
// If the user is holding down Shift, suppress mouse events
|
||||
// TODO GH#4875: disable/customize this functionality
|
||||
@@ -667,7 +667,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _core->ShouldSendAlternateScroll(WM_MOUSEWHEEL, delta);
|
||||
if (delta.Y != 0)
|
||||
{
|
||||
return _core->ShouldSendAlternateScroll(WM_MOUSEWHEEL, delta.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _core->ShouldSendAlternateScroll(WM_MOUSEHWHEEL, delta.X);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TouchReleased();
|
||||
|
||||
bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const int32_t delta,
|
||||
const Core::Point delta,
|
||||
const Core::Point pixelPosition,
|
||||
const Control::MouseButtonState state);
|
||||
|
||||
@@ -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 int32_t delta);
|
||||
bool _shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const Core::Point delta);
|
||||
|
||||
til::point _getTerminalPosition(const til::point pixelPosition, bool roundToNearestCell);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Microsoft.Terminal.Control
|
||||
void TouchReleased();
|
||||
|
||||
Boolean MouseWheel(Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Int32 delta,
|
||||
Microsoft.Terminal.Core.Point delta,
|
||||
Microsoft.Terminal.Core.Point pixelPosition,
|
||||
MouseButtonState state);
|
||||
|
||||
|
||||
@@ -462,6 +462,11 @@ void HwndTerminal::SendOutput(std::wstring_view data)
|
||||
_terminal->Write(data);
|
||||
}
|
||||
|
||||
void _stdcall AvoidBuggyTSFConsoleFlags()
|
||||
{
|
||||
Microsoft::Console::TSF::Handle::AvoidBuggyTSFConsoleFlags();
|
||||
}
|
||||
|
||||
HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal)
|
||||
{
|
||||
auto publicTerminal = std::make_unique<HwndTerminal>(parentHwnd);
|
||||
|
||||
@@ -41,6 +41,7 @@ typedef struct _TerminalTheme
|
||||
} TerminalTheme, *LPTerminalTheme;
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllexport) void _stdcall AvoidBuggyTSFConsoleFlags();
|
||||
__declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal);
|
||||
__declspec(dllexport) void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data);
|
||||
__declspec(dllexport) void _stdcall TerminalRegisterScrollCallback(void* terminal, void __stdcall callback(int, int, int));
|
||||
|
||||
@@ -11,6 +11,6 @@ namespace Microsoft.Terminal.Control
|
||||
[uuid("65b8b8c5-988f-43ff-aba9-e89368da1598")]
|
||||
interface IMouseWheelListener
|
||||
{
|
||||
Boolean OnMouseWheel(Windows.Foundation.Point coord, Int32 delta, Boolean leftButtonDown, Boolean midButtonDown, Boolean rightButtonDown);
|
||||
Boolean OnMouseWheel(Windows.Foundation.Point coord, Microsoft.Terminal.Core.Point delta, Boolean leftButtonDown, Boolean midButtonDown, Boolean rightButtonDown);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2164,15 +2164,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
RestorePointerCursor.raise(*this, nullptr);
|
||||
|
||||
const auto point = args.GetCurrentPoint(*this);
|
||||
// GH#10329 - we don't need to handle horizontal scrolls. Only vertical ones.
|
||||
// So filter out the horizontal ones.
|
||||
if (point.Properties().IsHorizontalMouseWheel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto delta = point.Properties().MouseWheelDelta();
|
||||
auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() },
|
||||
point.Properties().MouseWheelDelta(),
|
||||
point.Properties().IsHorizontalMouseWheel() ?
|
||||
Core::Point{ delta, 0 } :
|
||||
Core::Point{ 0, delta },
|
||||
_toTerminalOrigin(point.Position()),
|
||||
TermControl::GetPressedMouseButtons(point));
|
||||
if (result)
|
||||
@@ -2192,7 +2188,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - delta: the mouse wheel delta that triggered this event.
|
||||
// - state: the state for each of the mouse buttons individually (pressed/unpressed)
|
||||
bool TermControl::OnMouseWheel(const Windows::Foundation::Point location,
|
||||
const int32_t delta,
|
||||
const Core::Point delta,
|
||||
const bool leftButtonDown,
|
||||
const bool midButtonDown,
|
||||
const bool rightButtonDown)
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
bool OnMouseWheel(const Windows::Foundation::Point location, const int32_t delta, const bool leftButtonDown, const bool midButtonDown, const bool rightButtonDown);
|
||||
bool OnMouseWheel(const Windows::Foundation::Point location, const winrt::Microsoft::Terminal::Core::Point delta, const bool leftButtonDown, const bool midButtonDown, const bool rightButtonDown);
|
||||
|
||||
~TermControl();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ EXPORTS
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
|
||||
; Flat C ABI
|
||||
AvoidBuggyTSFConsoleFlags
|
||||
CreateTerminal
|
||||
DestroyTerminal
|
||||
TerminalBlinkCursor
|
||||
|
||||
@@ -720,7 +720,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
_MarkDuplicateBellSoundDirectories();
|
||||
_CheckBellSoundsExistence();
|
||||
_NotifyChanges(L"CurrentBellSounds");
|
||||
}
|
||||
|
||||
@@ -732,19 +731,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
if (!_profile.HasBellSound())
|
||||
{
|
||||
std::vector<hstring> newSounds;
|
||||
std::vector<IMediaResource> newSounds;
|
||||
if (const auto inheritedSounds = _profile.BellSound())
|
||||
{
|
||||
// copy inherited bell sounds to the current layer
|
||||
newSounds.reserve(inheritedSounds.Size());
|
||||
for (const auto sound : inheritedSounds)
|
||||
{
|
||||
newSounds.push_back(sound);
|
||||
}
|
||||
newSounds = wil::to_vector(inheritedSounds);
|
||||
}
|
||||
// if we didn't inherit any bell sounds,
|
||||
// we should still set the bell sound to an empty list (instead of null)
|
||||
_profile.BellSound(winrt::single_threaded_vector<hstring>(std::move(newSounds)));
|
||||
_profile.BellSound(winrt::single_threaded_vector(std::move(newSounds)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,56 +762,35 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Check if the bell sounds exist on disk. Mark any that don't exist
|
||||
// so that they show the appropriate UI
|
||||
safe_void_coroutine ProfileViewModel::_CheckBellSoundsExistence()
|
||||
BellSoundViewModel::BellSoundViewModel(const Model::IMediaResource& resource) :
|
||||
_resource{ resource }
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
std::vector<Editor::BellSoundViewModel> markedSounds;
|
||||
for (auto&& sound : _CurrentBellSounds)
|
||||
if (_resource.Ok() && _resource.Path() != _resource.Resolved())
|
||||
{
|
||||
if (!std::filesystem::exists(std::wstring_view{ sound.Path() }))
|
||||
{
|
||||
markedSounds.push_back(sound);
|
||||
}
|
||||
// If the resource was resolved to something other than its path, show the path!
|
||||
_ShowDirectory = true;
|
||||
}
|
||||
|
||||
co_await winrt::resume_foreground(_dispatcher);
|
||||
for (auto&& sound : markedSounds)
|
||||
{
|
||||
get_self<BellSoundViewModel>(sound)->FileExists(false);
|
||||
}
|
||||
}
|
||||
|
||||
BellSoundViewModel::BellSoundViewModel(hstring path) :
|
||||
_Path{ path }
|
||||
{
|
||||
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
if (args.PropertyName() == L"FileExists")
|
||||
{
|
||||
_NotifyChanges(L"DisplayPath", L"SubText");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hstring BellSoundViewModel::DisplayPath() const
|
||||
{
|
||||
if (_FileExists)
|
||||
if (_resource.Ok())
|
||||
{
|
||||
// filename
|
||||
const std::filesystem::path filePath{ std::wstring_view{ _Path } };
|
||||
// filename; start from the resolved path to show where it actually landed
|
||||
auto resolvedPath{ _resource.Resolved() };
|
||||
const std::filesystem::path filePath{ std::wstring_view{ resolvedPath } };
|
||||
return hstring{ filePath.filename().wstring() };
|
||||
}
|
||||
return _Path;
|
||||
return _resource.Path();
|
||||
}
|
||||
|
||||
hstring BellSoundViewModel::SubText() const
|
||||
{
|
||||
if (_FileExists)
|
||||
if (_resource.Ok())
|
||||
{
|
||||
// Directory
|
||||
const std::filesystem::path filePath{ std::wstring_view{ _Path } };
|
||||
auto resolvedPath{ _resource.Resolved() };
|
||||
const std::filesystem::path filePath{ std::wstring_view{ resolvedPath } };
|
||||
return hstring{ filePath.parent_path().wstring() };
|
||||
}
|
||||
return RS_(L"Profile_BellSoundNotFound");
|
||||
@@ -825,17 +798,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
hstring ProfileViewModel::BellSoundPreview()
|
||||
{
|
||||
const auto& currentSound = BellSound();
|
||||
if (!currentSound || currentSound.Size() == 0)
|
||||
if (!_CurrentBellSounds || _CurrentBellSounds.Size() == 0)
|
||||
{
|
||||
return RS_(L"Profile_BellSoundPreviewDefault");
|
||||
}
|
||||
else if (currentSound.Size() == 1)
|
||||
if (_CurrentBellSounds.Size() > 1)
|
||||
{
|
||||
std::filesystem::path filePath{ std::wstring_view{ currentSound.GetAt(0) } };
|
||||
return hstring{ filePath.filename().wstring() };
|
||||
return RS_(L"Profile_BellSoundPreviewMultiple");
|
||||
}
|
||||
return RS_(L"Profile_BellSoundPreviewMultiple");
|
||||
|
||||
const auto currentBellSound = _CurrentBellSounds.GetAt(0);
|
||||
if (currentBellSound.FileExists())
|
||||
{
|
||||
return currentBellSound.DisplayPath();
|
||||
}
|
||||
|
||||
return RS_(L"Profile_BellSoundNotFound");
|
||||
}
|
||||
|
||||
void ProfileViewModel::RequestAddBellSound(hstring path)
|
||||
@@ -844,9 +822,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// copy it over to the current layer and apply modifications
|
||||
_PrepareModelForBellSoundModification();
|
||||
|
||||
// No need to check if the file exists. We came from the FilePicker. That's good enough.
|
||||
_CurrentBellSounds.Append(winrt::make<BellSoundViewModel>(path));
|
||||
_profile.BellSound().Append(path);
|
||||
auto bellResource{ MediaResourceHelper::FromString(path) };
|
||||
bellResource.Resolve(path); // No need to check if the file exists. We came from the FilePicker. That's good enough.
|
||||
_CurrentBellSounds.Append(winrt::make<BellSoundViewModel>(bellResource));
|
||||
_profile.BellSound().Append(bellResource);
|
||||
_NotifyChanges(L"CurrentBellSounds");
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
struct BellSoundViewModel : BellSoundViewModelT<BellSoundViewModel>, ViewModelHelper<BellSoundViewModel>
|
||||
{
|
||||
public:
|
||||
BellSoundViewModel(hstring path);
|
||||
BellSoundViewModel(const Model::IMediaResource& resource);
|
||||
|
||||
hstring Path() const { return _resource.Path(); }
|
||||
bool FileExists() const { return _resource.Ok(); }
|
||||
hstring DisplayPath() const;
|
||||
hstring SubText() const;
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, FileExists, true);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, Path);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, ShowDirectory);
|
||||
|
||||
private:
|
||||
Model::IMediaResource _resource;
|
||||
};
|
||||
|
||||
struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
|
||||
@@ -190,7 +193,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void _InitializeCurrentBellSounds();
|
||||
void _PrepareModelForBellSoundModification();
|
||||
void _MarkDuplicateBellSoundDirectories();
|
||||
safe_void_coroutine _CheckBellSoundsExistence();
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
|
||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
|
||||
static Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> _BuiltInIcons;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
|
||||
runtimeclass BellSoundViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
String Path;
|
||||
String Path { get; };
|
||||
String DisplayPath { get; };
|
||||
String SubText { get; };
|
||||
Boolean ShowDirectory { get; };
|
||||
@@ -149,7 +149,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.Collections.IVector<Microsoft.Terminal.Settings.Model.IMediaResource>, BellSound);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Elevate);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RightClickContextMenu);
|
||||
|
||||
@@ -371,7 +371,7 @@
|
||||
<value>入力したテキストをセルにグループ化する方法を変更します。"Grapheme clusters" オプションは最も新しく Unicode で正しい方法ですが、UNIX では "wcswidth" は一般的な方法であり、"Windows コンソール" は Windows での動作方法をレプリケートします。この設定を変更するには、Windows ターミナルの再起動が必要です。この設定は、その中から起動されたアプリケーションにのみ適用されます。</value>
|
||||
</data>
|
||||
<data name="Globals_TextMeasurement_Graphemes.Text" xml:space="preserve">
|
||||
<value>Grapheme クラスター</value>
|
||||
<value>書記素クラスター</value>
|
||||
<comment>The default choice between multiple graphics APIs.</comment>
|
||||
</data>
|
||||
<data name="Globals_TextMeasurement_Wcswidth.Text" xml:space="preserve">
|
||||
@@ -1338,7 +1338,7 @@
|
||||
<comment>"environment variables" are user-definable values that can affect the way running processes will behave on a computer</comment>
|
||||
</data>
|
||||
<data name="Profile_ReloadEnvVars.HelpText" xml:space="preserve">
|
||||
<value>有効にすると、ターミナルは、このプロファイルで新しいタブまたはウィンドウを作成するときに新しい環境ブロックを生成します。無効にすると、代わりにタブ/ペインはターミナルが開始された変数を継承します。</value>
|
||||
<value>有効にすると、ターミナルは、このプロファイルで新しいタブまたはペインを作成するときに新しい環境ブロックを生成します。無効にすると、代わりにタブ/ペインはターミナルが開始された変数を継承します。</value>
|
||||
<comment>A description for what the "Reload environment variables" setting does. Presented near "Profile_ReloadEnvVars".</comment>
|
||||
</data>
|
||||
<data name="Profile_RightClickContextMenu.Header" xml:space="preserve">
|
||||
@@ -1382,7 +1382,7 @@
|
||||
<comment>An option to choose from for the "bell style" setting. When selected, notifications are silenced.</comment>
|
||||
</data>
|
||||
<data name="Globals_DisableAnimations.Header" xml:space="preserve">
|
||||
<value>ウィンドウのアニメーションを無効にする</value>
|
||||
<value>ペインのアニメーションを無効にする</value>
|
||||
<comment>Header for a control to toggle animations on panes. "Enabled" value disables the animations.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontWeightBlack.Content" xml:space="preserve">
|
||||
@@ -1733,7 +1733,7 @@
|
||||
<comment>An error message that appears when the user attempts to rename a color scheme to something invalid. This appears as the title, and explains the issue.</comment>
|
||||
</data>
|
||||
<data name="Globals_FocusFollowMouse.Header" xml:space="preserve">
|
||||
<value>マウスをポイントしたときにフォーカス ウィンドウを自動的に表示する</value>
|
||||
<value>マウスをポイントしたときにフォーカス ペインを自動的に表示する</value>
|
||||
<comment>Header for a control to toggle the "focus follow mouse" setting. When enabled, hovering over a pane puts it in focus.</comment>
|
||||
</data>
|
||||
<data name="Globals_ScrollToZoom.Header" xml:space="preserve">
|
||||
@@ -1745,7 +1745,7 @@
|
||||
<comment>Header for a control to toggle opacity changes with scrolling. When enabled, holding the Ctrl and Shift keys while scrolling will increase or decrease the window opacity.</comment>
|
||||
</data>
|
||||
<data name="Globals_DisableAnimationsReversed.Header" xml:space="preserve">
|
||||
<value>ウィンドウのアニメーション</value>
|
||||
<value>ペインのアニメーション</value>
|
||||
<comment>Header for a control to toggle animations on panes. "Enabled" value enables the animations.</comment>
|
||||
</data>
|
||||
<data name="Globals_AlwaysShowNotificationIcon.Header" xml:space="preserve">
|
||||
|
||||
@@ -729,7 +729,7 @@
|
||||
<comment>A description for what the "antialiasing mode" setting does. Presented near "Profile_AntialiasingMode.Header".</comment>
|
||||
</data>
|
||||
<data name="Profile_AntialiasingModeAliased.Content" xml:space="preserve">
|
||||
<value>별칭</value>
|
||||
<value>앨리어싱</value>
|
||||
<comment>An option to choose from for the "text antialiasing" setting. When selected, the app's text renderer does not use antialiasing techniques.</comment>
|
||||
</data>
|
||||
<data name="Profile_AntialiasingModeClearType.Content" xml:space="preserve">
|
||||
|
||||
@@ -335,7 +335,7 @@
|
||||
<comment>This text is shown next to a list of choices.</comment>
|
||||
</data>
|
||||
<data name="Globals_GraphicsAPI.HelpText" xml:space="preserve">
|
||||
<value>Direct3D 11 提供更具效能且功能更豐富的體驗,而 Direct2D 則較穩定。默認選項 [自動] 會挑選最適合您圖形硬體的 API。如果您遇到重大問題,請考慮使用 Direct2D。</value>
|
||||
<value>Direct3D 11 提供更具效能且功能更豐富的體驗,而 Direct2D 則較穩定。預設選項 [自動] 會挑選最適合您圖形硬體的 API。如果您遇到重大問題,請考慮使用 Direct2D。</value>
|
||||
</data>
|
||||
<data name="Globals_GraphicsAPI_Automatic.Text" xml:space="preserve">
|
||||
<value>自動</value>
|
||||
@@ -1018,7 +1018,7 @@
|
||||
<comment>A description for what the "line height" setting does. Presented near "Profile_LineHeight".</comment>
|
||||
</data>
|
||||
<data name="Profile_CellWidth.HelpText" xml:space="preserve">
|
||||
<value>覆寫終端機的單元格寬度。以字型大小的倍數表示。默認值取決於您的字型,通常大約是0.6。</value>
|
||||
<value>覆寫終端機的單元格寬度。以字型大小的倍數表示。預設值取決於您的字型,通常大約是0.6。</value>
|
||||
<comment>A description for what the "cell width" setting does. Presented near "Profile_CellWidth".</comment>
|
||||
</data>
|
||||
<data name="Profile_LineHeightBox.PlaceholderText" xml:space="preserve">
|
||||
|
||||
@@ -82,18 +82,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
command->LogSettingChanges(_changeLog);
|
||||
AddAction(*command, keys);
|
||||
|
||||
if (jsonBlock.isMember(JsonKey(KeysKey)))
|
||||
{
|
||||
// there are keys in this command block meaning this is the legacy style -
|
||||
// inform the loader that fixups are needed
|
||||
_fixupsAppliedDuringLoad = true;
|
||||
}
|
||||
|
||||
if (jsonBlock.isMember(JsonKey(ActionKey)) && !jsonBlock.isMember(JsonKey(IterateOnKey)) && origin == OriginTag::User && !jsonBlock.isMember(JsonKey(IDKey)))
|
||||
if (jsonBlock.isMember(JsonKey(ActionKey)) && !jsonBlock.isMember(JsonKey(IterateOnKey)) && origin == OriginTag::User &&
|
||||
(!jsonBlock.isMember(JsonKey(IDKey)) || jsonBlock.isMember(JsonKey(KeysKey))))
|
||||
{
|
||||
// for non-nested non-iterable commands,
|
||||
// if there's no ID in the command block we will generate one for the user -
|
||||
// inform the loader that the ID needs to be written into the json
|
||||
// if there's no ID in the command block we will generate one for the user,
|
||||
// or if there are keys in this command block that means this is the legacy style -
|
||||
// in either case, inform the loader that fixups are needed
|
||||
_fixupsAppliedDuringLoad = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,6 +588,16 @@ static void _resolveSingleMediaResourceInner(Model::OriginTag origin, std::wstri
|
||||
}
|
||||
}
|
||||
|
||||
if (origin == winrt::Microsoft::Terminal::Settings::Model::OriginTag::Fragment)
|
||||
{
|
||||
if (PathIsUNCEx(resourcePath.c_str(), nullptr))
|
||||
{
|
||||
// A UNC path is just another type of network path, which fragments are not allowed to specify.
|
||||
resource.Reject();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a URI? Try a path.
|
||||
try
|
||||
{
|
||||
|
||||
@@ -559,6 +559,7 @@ bool SettingsLoader::AddDynamicProfileFolders()
|
||||
folderEntry->Inlining(FolderEntryInlining::Auto);
|
||||
folderEntry->RawEntries(winrt::single_threaded_vector<Model::NewTabMenuEntry>({ *matchProfilesEntry }));
|
||||
|
||||
// NewTabMenu is guaranteed to exist by FixupUserSettings, which runs before this fixup.
|
||||
userSettings.globals->NewTabMenu().Append(folderEntry.as<Model::NewTabMenuEntry>());
|
||||
state->SSHFolderGenerated(true);
|
||||
return true;
|
||||
@@ -689,6 +690,16 @@ bool SettingsLoader::FixupUserSettings()
|
||||
fixedUp = true;
|
||||
}
|
||||
|
||||
// Terminal 1.24
|
||||
// Ensure that the user always has a newTabMenu. We used to do this last, after
|
||||
// resolving all of the new tab menu entries, but there was no conceivable reason
|
||||
// that it should happen so late.
|
||||
if (!userSettings.globals->HasNewTabMenu())
|
||||
{
|
||||
userSettings.globals->NewTabMenu(winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} }));
|
||||
// This one does not need to be written back to the settings file immediately, it can wait until we write one for another reason.
|
||||
}
|
||||
|
||||
return fixedUp;
|
||||
}
|
||||
|
||||
@@ -1263,8 +1274,8 @@ try
|
||||
// DisableDeletedProfiles returns true whenever we encountered any new generated/dynamic profiles.
|
||||
// Similarly FixupUserSettings returns true, when it encountered settings that were patched up.
|
||||
mustWriteToDisk |= loader.DisableDeletedProfiles();
|
||||
mustWriteToDisk |= loader.AddDynamicProfileFolders();
|
||||
mustWriteToDisk |= loader.FixupUserSettings();
|
||||
mustWriteToDisk |= loader.AddDynamicProfileFolders();
|
||||
|
||||
// If this throws, the app will catch it and use the default settings.
|
||||
const auto settings = winrt::make_self<CascadiaSettings>(std::move(loader));
|
||||
@@ -1745,16 +1756,6 @@ void CascadiaSettings::_resolveNewTabMenuProfiles() const
|
||||
{
|
||||
remainingProfilesEntry.Profiles(remainingProfiles);
|
||||
}
|
||||
|
||||
// If the configuration does not have a "newTabMenu" field, GlobalAppSettings
|
||||
// will return a default value containing just a "remainingProfiles" entry. However,
|
||||
// this value is regenerated on every "get" operation, so the effect of setting
|
||||
// the remaining profiles above will be undone. So only in the case that no custom
|
||||
// value is present in GlobalAppSettings, we will store the modified default value.
|
||||
if (!_globals->HasNewTabMenu())
|
||||
{
|
||||
_globals->NewTabMenu(entries);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -95,7 +95,7 @@ Author(s):
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(IEnvironmentVariableMap, EnvironmentVariables, "environment", nullptr) \
|
||||
X(bool, RightClickContextMenu, "rightClickContextMenu", false) \
|
||||
X(Windows::Foundation::Collections::IVector<winrt::hstring>, BellSound, "bellSound", nullptr) \
|
||||
X(Windows::Foundation::Collections::IVector<IMediaResource>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, AutoMarkPrompts, "autoMarkPrompts", true) \
|
||||
X(bool, ShowMarks, "showMarksOnScrollbar", false) \
|
||||
|
||||
@@ -121,16 +121,10 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_COPY)
|
||||
#undef PROFILE_SETTINGS_COPY
|
||||
|
||||
// BellSound is an IVector<hstring>, so we need to manually copy it over
|
||||
if (_BellSound)
|
||||
{
|
||||
std::vector<hstring> sounds;
|
||||
sounds.reserve(_BellSound->Size());
|
||||
for (const auto& sound : *_BellSound)
|
||||
{
|
||||
sounds.emplace_back(sound);
|
||||
}
|
||||
profile->_BellSound = single_threaded_vector(std::move(sounds));
|
||||
// BellSound is an IVector<>, so we need to make a new vector pointing at the same objects
|
||||
profile->_BellSound = winrt::single_threaded_vector(wil::to_vector(*_BellSound));
|
||||
}
|
||||
|
||||
if (_UnfocusedAppearance)
|
||||
@@ -560,6 +554,16 @@ void Profile::ResolveMediaResources(const Model::MediaResourceResolver& resolver
|
||||
{
|
||||
container->ResolveMediaResources(resolver);
|
||||
}
|
||||
|
||||
if (const auto [bellSoundSource, bellSounds]{ _getBellSoundOverrideSourceAndValueImpl() };
|
||||
bellSoundSource && bellSounds && *bellSounds && bellSounds->Size() > 0)
|
||||
{
|
||||
for (const auto& bellSound : *bellSounds)
|
||||
{
|
||||
ResolveMediaResource(bellSoundSource->_Origin, bellSoundSource->SourceBasePath, bellSound, resolver);
|
||||
}
|
||||
// It's important that we keep the invalid bell sounds in the list, because we may want to write it back out to disk
|
||||
}
|
||||
}
|
||||
|
||||
void Profile::LogSettingChanges(std::set<std::string>& changes, const std::string_view& context) const
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IMap<String COMMA String>, EnvironmentVariables);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
|
||||
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<IMediaResource>, BellSound);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, Elevate);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AutoMarkPrompts);
|
||||
|
||||
@@ -124,10 +124,10 @@
|
||||
<value>新しいタブ...</value>
|
||||
</data>
|
||||
<data name="SplitPaneParentCommandName" xml:space="preserve">
|
||||
<value>ウィンドウの分割...</value>
|
||||
<value>ペインの分割...</value>
|
||||
</data>
|
||||
<data name="SnippetsPaneCommandName" xml:space="preserve">
|
||||
<value>スニペット ウィンドウを開く</value>
|
||||
<value>スニペット ペインを開く</value>
|
||||
<comment>This will open a pane with a list of the users's saved commands ("snippets") in it</comment>
|
||||
</data>
|
||||
<data name="ApplicationDisplayNamePortable" xml:space="preserve">
|
||||
@@ -153,7 +153,7 @@
|
||||
<value>他のすべてのタブを閉じる</value>
|
||||
</data>
|
||||
<data name="ClosePaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを閉じる</value>
|
||||
<value>ペインを閉じる</value>
|
||||
</data>
|
||||
<data name="CloseTabAtIndexCommandKey" xml:space="preserve">
|
||||
<value>インデックス {0}のタブを閉じる</value>
|
||||
@@ -229,7 +229,7 @@
|
||||
<value>以前</value>
|
||||
</data>
|
||||
<data name="DuplicatePaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウの複製する</value>
|
||||
<value>ペインの複製する</value>
|
||||
</data>
|
||||
<data name="DuplicateTabCommandKey" xml:space="preserve">
|
||||
<value>タブを複製する</value>
|
||||
@@ -262,41 +262,41 @@
|
||||
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", "DirectionDown"</comment>
|
||||
</data>
|
||||
<data name="MoveFocusToLastUsedPane" xml:space="preserve">
|
||||
<value>前回使用したウィンドウにフォーカスを移動する</value>
|
||||
<value>前回使用したペインにフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="MoveFocusNextInOrder" xml:space="preserve">
|
||||
<value>次のウィンドウに順番にフォーカスを移動する</value>
|
||||
<value>次のペインに順番にフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="MoveFocusPreviousInOrder" xml:space="preserve">
|
||||
<value>前のウィンドウに順番にフォーカスを移動する</value>
|
||||
<value>前のペインに順番にフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="MoveFocusFirstPane" xml:space="preserve">
|
||||
<value>最初のウィンドウにフォーカスを移動する</value>
|
||||
<value>最初のペインにフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="MoveFocusParentPane" xml:space="preserve">
|
||||
<value>親ウィンドウにフォーカスを移動する</value>
|
||||
<value>親ペインにフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="MoveFocusChildPane" xml:space="preserve">
|
||||
<value>子ウィンドウにフォーカスを移動する</value>
|
||||
<value>子ペインにフォーカスを移動する</value>
|
||||
</data>
|
||||
<data name="SwapPaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを入れ替える</value>
|
||||
<value>ペインを入れ替える</value>
|
||||
</data>
|
||||
<data name="SwapPaneWithArgCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを入れ替える {0}</value>
|
||||
<value>ペインを入れ替える {0}</value>
|
||||
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", "DirectionDown"</comment>
|
||||
</data>
|
||||
<data name="SwapPaneToLastUsedPane" xml:space="preserve">
|
||||
<value>ウィンドウを最後に使用したウィンドウと入れ替える</value>
|
||||
<value>ペインを最後に使用したペインと入れ替える</value>
|
||||
</data>
|
||||
<data name="SwapPaneNextInOrder" xml:space="preserve">
|
||||
<value>ウィンドウを次のウィンドウと順番に入れ替える</value>
|
||||
<value>ペインを次のペインと順番に入れ替える</value>
|
||||
</data>
|
||||
<data name="SwapPanePreviousInOrder" xml:space="preserve">
|
||||
<value>ウィンドウを前のウィンドウと順番に入れ替える</value>
|
||||
<value>ペインを前のペインと順番に入れ替える</value>
|
||||
</data>
|
||||
<data name="SwapPaneFirstPane" xml:space="preserve">
|
||||
<value>最初のウィンドウとウィンドウを入れ替える</value>
|
||||
<value>最初のペインとペインを入れ替える</value>
|
||||
</data>
|
||||
<data name="NewTabCommandKey" xml:space="preserve">
|
||||
<value>新しいタブ</value>
|
||||
@@ -357,10 +357,10 @@
|
||||
<value>タブ名を変更</value>
|
||||
</data>
|
||||
<data name="ResizePaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウのサイズの変更する</value>
|
||||
<value>ペインのサイズの変更する</value>
|
||||
</data>
|
||||
<data name="ResizePaneWithArgCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウのサイズを変更する {0}</value>
|
||||
<value>ペインのサイズを変更する {0}</value>
|
||||
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown"</comment>
|
||||
</data>
|
||||
<data name="ScrollDownCommandKey" xml:space="preserve">
|
||||
@@ -427,19 +427,19 @@
|
||||
<comment>{0} will be replaced with a color, displayed in hexadecimal (#RRGGBB) notation.</comment>
|
||||
</data>
|
||||
<data name="SplitHorizontalCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを左右に分割</value>
|
||||
<value>ペインを左右に分割</value>
|
||||
</data>
|
||||
<data name="MovePaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウの移動</value>
|
||||
<value>ペインの移動</value>
|
||||
</data>
|
||||
<data name="MovePaneToNewWindowCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを新しいウィンドウに移動</value>
|
||||
<value>ペインを新しいウィンドウに移動</value>
|
||||
</data>
|
||||
<data name="SplitPaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを分割する</value>
|
||||
<value>ペインを分割する</value>
|
||||
</data>
|
||||
<data name="SplitVerticalCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを上下に分割</value>
|
||||
<value>ペインを上下に分割</value>
|
||||
</data>
|
||||
<data name="SwitchToTabCommandKey" xml:space="preserve">
|
||||
<value>タブに切り替え</value>
|
||||
@@ -488,19 +488,19 @@
|
||||
<value>最大化ウィンドウを復元する</value>
|
||||
</data>
|
||||
<data name="ToggleSplitOrientationCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウ分割の方向の切り替え</value>
|
||||
<value>ペイン分割の方向の切り替え</value>
|
||||
</data>
|
||||
<data name="TogglePaneZoomCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウのズームの切り替え</value>
|
||||
<value>ペインのズームの切り替え</value>
|
||||
</data>
|
||||
<data name="TogglePaneReadOnlyCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウを読み取り専用モードに切り替える</value>
|
||||
<value>ペインを読み取り専用モードに切り替える</value>
|
||||
</data>
|
||||
<data name="EnablePaneReadOnlyCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウの読み取り専用モードを有効にする</value>
|
||||
<value>ペインの読み取り専用モードを有効にする</value>
|
||||
</data>
|
||||
<data name="DisablePaneReadOnlyCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウの読み取り専用モードを無効にする</value>
|
||||
<value>ペインの読み取り専用モードを無効にする</value>
|
||||
</data>
|
||||
<data name="ToggleShaderEffectsCommandKey" xml:space="preserve">
|
||||
<value>ターミナルの視覚効果の切り替え</value>
|
||||
@@ -532,7 +532,7 @@
|
||||
<comment>Quake is a well-known computer game and isn't related to earthquakes, etc. See https://en.wikipedia.org/wiki/Quake_(video_game)</comment>
|
||||
</data>
|
||||
<data name="FocusPaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウ {0} をフォーカスする</value>
|
||||
<value>ペイン {0} をフォーカスする</value>
|
||||
<comment>{0} will be replaced with a user-specified number</comment>
|
||||
</data>
|
||||
<data name="ExportBufferToPathCommandKey" xml:space="preserve">
|
||||
@@ -585,7 +585,7 @@
|
||||
<comment>A command to change how transparent the background of the window is</comment>
|
||||
</data>
|
||||
<data name="RestoreLastClosedCommandKey" xml:space="preserve">
|
||||
<value>最後に閉じたウィンドウまたはタブを復元する</value>
|
||||
<value>最後に閉じたペインまたはタブを復元する</value>
|
||||
</data>
|
||||
<data name="SelectAllCommandKey" xml:space="preserve">
|
||||
<value>すべてのテキストを選択</value>
|
||||
@@ -695,10 +695,10 @@
|
||||
<value>コンテキスト メニューの表示</value>
|
||||
</data>
|
||||
<data name="CloseOtherPanesCommandKey" xml:space="preserve">
|
||||
<value>他のすべてのウィンドウを閉じる</value>
|
||||
<value>他のすべてのペインを閉じる</value>
|
||||
</data>
|
||||
<data name="ToggleBroadcastInputCommandKey" xml:space="preserve">
|
||||
<value>ブロードキャスト入力をすべてのウィンドウに切り替える</value>
|
||||
<value>ブロードキャスト入力をすべてのペインに切り替える</value>
|
||||
<comment>When enabled, input will go to all panes in this tab simultaneously</comment>
|
||||
</data>
|
||||
<data name="RestartConnectionKey" xml:space="preserve">
|
||||
@@ -760,4 +760,4 @@
|
||||
<value>SSH ホスト プロファイル ジェネレーター</value>
|
||||
<comment>The display name of a dynamic profile generator for SSH hosts</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -35,19 +35,14 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
/*static*/ const std::wregex SshHostGenerator::_configKeyValueRegex{ LR"(^\s*(\w+)\s+([^\s]+.*[^\s])\s*$)" };
|
||||
|
||||
/*static*/ std::wstring_view SshHostGenerator::_getProfileName(const std::wstring_view& hostName) noexcept
|
||||
winrt::hstring _getProfileName(const std::wstring_view& hostName) noexcept
|
||||
{
|
||||
return std::wstring_view{ L"" + PROFILE_TITLE_PREFIX + hostName };
|
||||
return winrt::hstring{ fmt::format(FMT_COMPILE(L"{0}{1}"), PROFILE_TITLE_PREFIX, hostName) };
|
||||
}
|
||||
|
||||
/*static*/ std::wstring_view SshHostGenerator::_getProfileIconPath() noexcept
|
||||
winrt::hstring _getProfileCommandLine(const std::wstring_view& sshExePath, const std::wstring_view& hostName) noexcept
|
||||
{
|
||||
return PROFILE_ICON_PATH;
|
||||
}
|
||||
|
||||
/*static*/ std::wstring_view SshHostGenerator::_getProfileCommandLine(const std::wstring_view& sshExePath, const std::wstring_view& hostName) noexcept
|
||||
{
|
||||
return std::wstring_view{ L"\"" + sshExePath + L"\" " + hostName };
|
||||
return winrt::hstring{ fmt::format(FMT_COMPILE(LR"("{0}" {1})"), sshExePath, hostName) };
|
||||
}
|
||||
|
||||
/*static*/ bool SshHostGenerator::_tryFindSshExePath(std::wstring& sshExePath) noexcept
|
||||
@@ -164,8 +159,8 @@ void SshHostGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementatio
|
||||
{
|
||||
const auto profile{ CreateDynamicProfile(_getProfileName(hostName)) };
|
||||
|
||||
profile->Commandline(winrt::hstring{ _getProfileCommandLine(sshExePath, hostName) });
|
||||
profile->Icon(winrt::hstring{ _getProfileIconPath() });
|
||||
profile->Commandline(_getProfileCommandLine(sshExePath, hostName));
|
||||
profile->Icon(winrt::hstring{ PROFILE_ICON_PATH });
|
||||
|
||||
profiles.emplace_back(profile);
|
||||
}
|
||||
|
||||
@@ -31,10 +31,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model
|
||||
private:
|
||||
static const std::wregex _configKeyValueRegex;
|
||||
|
||||
static std::wstring_view _getProfileName(const std::wstring_view& hostName) noexcept;
|
||||
static std::wstring_view _getProfileIconPath() noexcept;
|
||||
static std::wstring_view _getProfileCommandLine(const std::wstring_view& sshExePath, const std::wstring_view& hostName) noexcept;
|
||||
|
||||
static bool _tryFindSshExePath(std::wstring& sshExePath) noexcept;
|
||||
static bool _tryParseConfigKeyValue(const std::wstring_view& line, std::wstring& key, std::wstring& value) noexcept;
|
||||
static void _getHostNamesFromConfigFile(const std::wstring_view& configPath, std::vector<std::wstring>& hostNames) noexcept;
|
||||
|
||||
@@ -26,12 +26,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model
|
||||
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
|
||||
|
||||
private:
|
||||
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance&) const
|
||||
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const
|
||||
{
|
||||
// We only support version of VS from 15.0.
|
||||
// Per heaths: The [ISetupConfiguration] COM server only supports Visual Studio 15.0 and newer anyway.
|
||||
// Eliding the version range will improve the discovery performance by not having to parse or compare the versions.
|
||||
return true;
|
||||
std::error_code ec;
|
||||
return std::filesystem::exists(GetDevCmdScriptPath(instance), ec) && !ec;
|
||||
}
|
||||
|
||||
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model
|
||||
private:
|
||||
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const
|
||||
{
|
||||
return instance.VersionInRange(L"[16.2,)");
|
||||
std::error_code ec;
|
||||
return instance.VersionInRange(L"[16.2,)") && std::filesystem::exists(GetDevShellModulePath(instance), ec) && !ec;
|
||||
}
|
||||
|
||||
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
"background": "#141414",
|
||||
"foreground": "#BAB7B6",
|
||||
"cursorColor": "#37E57B",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"selectionBackground": "#8DB8E5",
|
||||
"black": "#000000",
|
||||
"red": "#CF494C",
|
||||
"green": "#60B442",
|
||||
@@ -101,7 +101,7 @@
|
||||
"brightBlue": "#688DFD",
|
||||
"brightPurple": "#ED6FE9",
|
||||
"brightCyan": "#32E0FB",
|
||||
"brightWhite": "#D3D8D9"
|
||||
"brightWhite": "#DEE3E4"
|
||||
},
|
||||
{
|
||||
"name": "Ottosson",
|
||||
|
||||
@@ -86,4 +86,5 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
<Import Project="$(OpenConsoleDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace ControlUnitTests
|
||||
|
||||
// The mouse location and buttons don't matter here.
|
||||
interactivity->MouseWheel(modifiers,
|
||||
30,
|
||||
Core::Point{ 0, 30 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
@@ -188,7 +188,7 @@ namespace ControlUnitTests
|
||||
|
||||
// The mouse location and buttons don't matter here.
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-30,
|
||||
Core::Point{ 0, -30 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
@@ -245,7 +245,7 @@ namespace ControlUnitTests
|
||||
expectedTop = 20;
|
||||
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
|
||||
@@ -254,18 +254,18 @@ namespace ControlUnitTests
|
||||
{
|
||||
expectedTop--;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
Log::Comment(L"Scrolling up more should do nothing");
|
||||
expectedTop = 0;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace ControlUnitTests
|
||||
Log::Comment(NoThrowString().Format(L"---scroll down #%d---", i));
|
||||
expectedTop++;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
Core::Point{ 0, -WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
Log::Comment(NoThrowString().Format(L"internal scrollbar pos:%f", interactivity->_internalScrollbarPosition));
|
||||
@@ -283,11 +283,11 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Scrolling down more should do nothing");
|
||||
expectedTop = 21;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
Core::Point{ 0, -WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
Core::Point{ 0, -WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
@@ -444,7 +444,7 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Scroll up a line, with the left mouse button selected");
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
cursorPosition1.to_core_point(),
|
||||
leftMouseDown);
|
||||
|
||||
@@ -492,55 +492,55 @@ namespace ControlUnitTests
|
||||
const Core::Point mousePos{ 0, 0 };
|
||||
Control::MouseButtonState state{};
|
||||
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 1/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
|
||||
Log::Comment(L"Scroll up 4 more times. Once we're at 3/5 scrolls, "
|
||||
L"we'll round the internal scrollbar position to scrolling to the next row.");
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 2/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 2/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 3/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 3/5
|
||||
VERIFY_ARE_EQUAL(20, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 4/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 4/5
|
||||
VERIFY_ARE_EQUAL(20, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 5/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 5/5
|
||||
VERIFY_ARE_EQUAL(20, core->ScrollOffset());
|
||||
|
||||
Log::Comment(L"Jump to line 5, so we can scroll down from there.");
|
||||
interactivity->UpdateScrollbar(5);
|
||||
VERIFY_ARE_EQUAL(5, core->ScrollOffset());
|
||||
Log::Comment(L"Scroll down 5 times, at which point we should accumulate a whole row of delta.");
|
||||
interactivity->MouseWheel(modifiers, -delta, mousePos, state); // 1/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, -delta }, mousePos, state); // 1/5
|
||||
VERIFY_ARE_EQUAL(5, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, -delta, mousePos, state); // 2/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, -delta }, mousePos, state); // 2/5
|
||||
VERIFY_ARE_EQUAL(5, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, -delta, mousePos, state); // 3/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, -delta }, mousePos, state); // 3/5
|
||||
VERIFY_ARE_EQUAL(6, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, -delta, mousePos, state); // 4/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, -delta }, mousePos, state); // 4/5
|
||||
VERIFY_ARE_EQUAL(6, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, -delta, mousePos, state); // 5/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, -delta }, mousePos, state); // 5/5
|
||||
VERIFY_ARE_EQUAL(6, core->ScrollOffset());
|
||||
|
||||
Log::Comment(L"Jump to the bottom.");
|
||||
interactivity->UpdateScrollbar(21);
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
Log::Comment(L"Scroll a bit, then emit a line of text. We should reset our internal scroll position.");
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 1/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 2/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 2/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
|
||||
conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n"));
|
||||
VERIFY_ARE_EQUAL(22, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 1/5
|
||||
VERIFY_ARE_EQUAL(22, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 2/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 2/5
|
||||
VERIFY_ARE_EQUAL(22, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 3/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 3/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 4/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 4/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 5/5
|
||||
interactivity->MouseWheel(modifiers, Core::Point{ 0, delta }, mousePos, state); // 5/5
|
||||
VERIFY_ARE_EQUAL(21, core->ScrollOffset());
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ namespace ControlUnitTests
|
||||
{
|
||||
expectedTop--;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
Core::Point{ 0, WHEEL_DELTA },
|
||||
Core::Point{ 0, 0 },
|
||||
noMouseDown);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace SettingsModelUnitTests
|
||||
TEST_METHOD(ProfileInheritsInvalidIconAndHasNoCommandline);
|
||||
TEST_METHOD(ProfileSpecifiesNullIcon);
|
||||
TEST_METHOD(ProfileSpecifiesNullIconAndHasNoCommandline);
|
||||
TEST_METHOD(ProfileOverwritesBellSound);
|
||||
|
||||
// FRAGMENT BEHAVIORS
|
||||
TEST_METHOD(FragmentUpdatesBaseProfile);
|
||||
@@ -102,6 +103,7 @@ namespace SettingsModelUnitTests
|
||||
TEST_METHOD(RealResolverFilePaths);
|
||||
TEST_METHOD(RealResolverSpecialKeywords);
|
||||
TEST_METHOD(RealResolverUrlCases);
|
||||
TEST_METHOD(RealResolverUNCCases);
|
||||
|
||||
static constexpr std::wstring_view pingCommandline{ LR"(C:\Windows\System32\PING.EXE)" }; // Normalized by Profile (this is the casing that Windows stores on disk)
|
||||
static constexpr std::wstring_view overrideCommandline{ LR"(C:\Windows\System32\cscript.exe)" };
|
||||
@@ -125,7 +127,11 @@ namespace SettingsModelUnitTests
|
||||
"backgroundImage": "imagePathFromBase",
|
||||
"guid": "{862d46aa-cc9c-4e6c-b872-9cadaafcdbbe}",
|
||||
"icon": "iconFromBase",
|
||||
"name": "Base"
|
||||
"name": "Base",
|
||||
"bellSound": [
|
||||
"C:\\Windows\\Media\\Alarm01.wav",
|
||||
"C:\\Windows\\Media\\Alarm02.wav"
|
||||
]
|
||||
},
|
||||
{
|
||||
"backgroundImage": "focusedImagePathFromBase",
|
||||
@@ -167,7 +173,7 @@ namespace SettingsModelUnitTests
|
||||
]
|
||||
})" };
|
||||
|
||||
static constexpr int numberOfMediaResourcesInDefaultSettings{ 9 };
|
||||
static constexpr int numberOfMediaResourcesInDefaultSettings{ 11 };
|
||||
|
||||
struct Fragment
|
||||
{
|
||||
@@ -1021,6 +1027,37 @@ namespace SettingsModelUnitTests
|
||||
VERIFY_IS_TRUE(icon.Ok()); // Profile with commandline always has an icon
|
||||
VERIFY_ARE_EQUAL(cmdCommandline, icon.Resolved());
|
||||
}
|
||||
|
||||
// A profile replaces the bell sounds (2) in the base settings; all bell sounds retained
|
||||
void MediaResourceTests::ProfileOverwritesBellSound()
|
||||
{
|
||||
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
|
||||
winrt::com_ptr<implementation::CascadiaSettings> settings;
|
||||
{
|
||||
auto [t, e] = requireCalled([&](auto&&, auto&&, auto&& resource) {
|
||||
// All resources are invalid.
|
||||
resource.Reject();
|
||||
});
|
||||
g_mediaResolverHook = t;
|
||||
settings = createSettings(R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"guid": "{862d46aa-cc9c-4e6c-b872-9cadaafcdbbe}",
|
||||
"bellSound": [
|
||||
"does not matter; resolved rejected"
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
})");
|
||||
}
|
||||
|
||||
auto profile{ settings->GetProfileByName(L"Base") };
|
||||
auto bellSounds{ profile.BellSound() };
|
||||
VERIFY_ARE_EQUAL(1u, bellSounds.Size());
|
||||
VERIFY_IS_FALSE(bellSounds.GetAt(0).Ok());
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Real Resolver Tests
|
||||
@@ -1306,5 +1343,95 @@ namespace SettingsModelUnitTests
|
||||
VERIFY_ARE_NOT_EQUAL(image.Resolved(), image.Path());
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceTests::RealResolverUNCCases()
|
||||
{
|
||||
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
|
||||
|
||||
g_mediaResolverHook = nullptr; // Use the real resolver
|
||||
|
||||
// For profile, we test images instead of icon because Icon has a fallback behavior.
|
||||
auto settings = createSettingsWithFragments(R"({})", { Fragment{ L"fragment", fragmentBasePath1, R"(
|
||||
{
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"backgroundImage": "\\\\server",
|
||||
"name": "ProfileUNCServerOnly"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\server\\share",
|
||||
"name": "ProfileUNCServerShare"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\server\\share\\file",
|
||||
"name": "ProfileUNCFullPath"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\?\\UNC\\server",
|
||||
"name": "ProfileWin32NamespaceUNCServerOnly"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\?\\UNC\\server\\share",
|
||||
"name": "ProfileWin32NamespaceUNCServerShare"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\?\\UNC\\server\\share\\file",
|
||||
"name": "ProfileWin32NamespaceUNCFullPath"
|
||||
},
|
||||
{
|
||||
"backgroundImage": "\\\\?\\C:\\Windows\\System32\\cmd.exe",
|
||||
"name": "ProfileWin32NamespaceDrivePath"
|
||||
},
|
||||
]
|
||||
}
|
||||
})" } });
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileUNCServerOnly") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileUNCServerShare") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileUNCFullPath") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCServerOnly") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCServerShare") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCFullPath") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_FALSE(image.Ok());
|
||||
}
|
||||
|
||||
// The only one of these paths which is OK is the one to \\?\C:\Windows
|
||||
{
|
||||
auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceDrivePath") };
|
||||
auto image{ profile.DefaultAppearance().BackgroundImagePath() };
|
||||
VERIFY_IS_TRUE(image.Ok());
|
||||
}
|
||||
|
||||
// We cannot test that user-originated UNC paths resolve properly because we cannot guarantee
|
||||
// the existence of a network share on any test machine, be it in a lab or owned by a user.
|
||||
}
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ void AppHost::_RaiseVisualBell(const winrt::Windows::Foundation::IInspectable&,
|
||||
// - delta: the wheel delta that triggered this event.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppHost::_WindowMouseWheeled(const winrt::Windows::Foundation::Point coord, const int32_t delta)
|
||||
void AppHost::_WindowMouseWheeled(const winrt::Windows::Foundation::Point coord, const winrt::Microsoft::Terminal::Core::Point delta)
|
||||
{
|
||||
if (_windowLogic)
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ private:
|
||||
|
||||
void _RaiseVisualBell(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
void _WindowMouseWheeled(const winrt::Windows::Foundation::Point coord, const int32_t delta);
|
||||
void _WindowMouseWheeled(const winrt::Windows::Foundation::Point coord, const winrt::Microsoft::Terminal::Core::Point delta);
|
||||
void _WindowActivated(bool activated);
|
||||
void _WindowMoved();
|
||||
|
||||
|
||||
@@ -595,6 +595,7 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam
|
||||
WindowCloseButtonClicked.raise();
|
||||
return 0;
|
||||
}
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_MOUSEWHEEL:
|
||||
try
|
||||
{
|
||||
@@ -623,7 +624,11 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam
|
||||
const auto scale = GetCurrentDpiScale();
|
||||
const winrt::Windows::Foundation::Point real{ relative.x / scale, relative.y / scale };
|
||||
|
||||
const auto wheelDelta = static_cast<short>(HIWORD(wparam));
|
||||
winrt::Microsoft::Terminal::Core::Point wheelDelta{ 0, std::bit_cast<int16_t>(HIWORD(wparam)) };
|
||||
if (message == WM_MOUSEHWHEEL)
|
||||
{
|
||||
std::swap(wheelDelta.X, wheelDelta.Y);
|
||||
}
|
||||
|
||||
// Raise an event, so any listeners can handle the mouse wheel event manually.
|
||||
MouseScrolled.raise(real, wheelDelta);
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
|
||||
til::event<winrt::delegate<>> DragRegionClicked;
|
||||
til::event<winrt::delegate<>> WindowCloseButtonClicked;
|
||||
til::event<winrt::delegate<void(winrt::Windows::Foundation::Point, int32_t)>> MouseScrolled;
|
||||
til::event<winrt::delegate<void(winrt::Windows::Foundation::Point, winrt::Microsoft::Terminal::Core::Point)>> MouseScrolled;
|
||||
til::event<winrt::delegate<void(bool)>> WindowActivated;
|
||||
til::event<winrt::delegate<void()>> NotifyNotificationIconPressed;
|
||||
til::event<winrt::delegate<void()>> NotifyWindowHidden;
|
||||
|
||||
@@ -194,6 +194,22 @@ static wil::unique_mutex acquireMutexOrAttemptHandoff(const wchar_t* className,
|
||||
return {};
|
||||
}
|
||||
|
||||
static constexpr bool IsInputKey(WORD vkey) noexcept
|
||||
{
|
||||
return vkey != VK_CONTROL &&
|
||||
vkey != VK_LCONTROL &&
|
||||
vkey != VK_RCONTROL &&
|
||||
vkey != VK_MENU &&
|
||||
vkey != VK_LMENU &&
|
||||
vkey != VK_RMENU &&
|
||||
vkey != VK_SHIFT &&
|
||||
vkey != VK_LSHIFT &&
|
||||
vkey != VK_RSHIFT &&
|
||||
vkey != VK_LWIN &&
|
||||
vkey != VK_RWIN &&
|
||||
vkey != VK_SNAPSHOT;
|
||||
}
|
||||
|
||||
HWND WindowEmperor::GetMainWindow() const noexcept
|
||||
{
|
||||
_assertIsMainThread();
|
||||
@@ -253,6 +269,29 @@ void WindowEmperor::CreateNewWindow(winrt::TerminalApp::WindowRequestedArgs args
|
||||
|
||||
_windowCount += 1;
|
||||
_windows.emplace_back(std::move(host));
|
||||
|
||||
if (_windowCount == 1)
|
||||
{
|
||||
// The first CoreWindow is created implicitly by XAML and parented to the
|
||||
// first XAML island. We parent it to our initial window for 2 reasons:
|
||||
// * On Windows 10 the CoreWindow will show up as a visible window on the taskbar
|
||||
// due to a WinUI bug, and this will hide it, because our initial window is hidden.
|
||||
// * When we DestroyWindow() the island it will destroy the CoreWindow,
|
||||
// and it's not possible to recreate it. That's also a WinUI bug.
|
||||
//
|
||||
// Note that this must be done after the first window (= first island) is created.
|
||||
if (const auto coreWindow = winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread())
|
||||
{
|
||||
if (const auto interop = coreWindow.try_as<ICoreWindowInterop>())
|
||||
{
|
||||
HWND coreHandle = nullptr;
|
||||
if (SUCCEEDED(interop->get_WindowHandle(&coreHandle)) && coreHandle)
|
||||
{
|
||||
SetParent(coreHandle, _window.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AppHost* WindowEmperor::_mostRecentWindow() const noexcept
|
||||
@@ -292,7 +331,7 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
}
|
||||
if (!IsPackaged())
|
||||
{
|
||||
const auto path = wil::GetModuleFileNameW<std::wstring>(nullptr);
|
||||
const auto path = wil::QueryFullProcessImageNameW<std::wstring>();
|
||||
const auto hash = til::hash(path);
|
||||
#ifdef _WIN64
|
||||
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:016x}"), hash);
|
||||
@@ -395,24 +434,6 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectoryW(system32.c_str()));
|
||||
}
|
||||
|
||||
// The first CoreWindow is created implicitly by XAML and parented to the
|
||||
// first XAML island. We parent it to our initial window for 2 reasons:
|
||||
// * On Windows 10 the CoreWindow will show up as a visible window on the taskbar
|
||||
// due to a WinUI bug, and this will hide it, because our initial window is hidden.
|
||||
// * When we DestroyWindow() the island it will destroy the CoreWindow,
|
||||
// and it's not possible to recreate it. That's also a WinUI bug.
|
||||
if (const auto coreWindow = winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread())
|
||||
{
|
||||
if (const auto interop = coreWindow.try_as<ICoreWindowInterop>())
|
||||
{
|
||||
HWND coreHandle = nullptr;
|
||||
if (SUCCEEDED(interop->get_WindowHandle(&coreHandle)) && coreHandle)
|
||||
{
|
||||
SetParent(coreHandle, _window.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TerminalConnection::ConptyConnection::NewConnection([this](TerminalConnection::ConptyConnection conn) {
|
||||
TerminalApp::CommandlineArgs args;
|
||||
@@ -481,7 +502,13 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
|
||||
if (msg.message == WM_KEYDOWN)
|
||||
{
|
||||
IslandWindow::HideCursor();
|
||||
const auto vkey = static_cast<WORD>(msg.wParam);
|
||||
|
||||
// Hide the cursor only when the key pressed is an input key (ignore modifier keys).
|
||||
if (IsInputKey(vkey))
|
||||
{
|
||||
IslandWindow::HideCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,6 +571,8 @@ void WindowEmperor::_dispatchSpecialKey(const MSG& msg) const
|
||||
|
||||
void WindowEmperor::_dispatchCommandline(winrt::TerminalApp::CommandlineArgs args)
|
||||
{
|
||||
_assertIsMainThread();
|
||||
|
||||
const auto exitCode = args.ExitCode();
|
||||
|
||||
if (const auto msg = args.ExitMessage(); !msg.empty())
|
||||
@@ -641,7 +670,8 @@ void WindowEmperor::_dispatchCommandlineCommon(winrt::array_view<const winrt::hs
|
||||
// This is an implementation-detail of _dispatchCommandline().
|
||||
safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args)
|
||||
{
|
||||
std::weak_ptr<AppHost> mostRecentWeak;
|
||||
std::shared_ptr<AppHost> mostRecent;
|
||||
AppHost* window = nullptr;
|
||||
|
||||
if (winrt::guid currentDesktop; VirtualDesktopUtils::GetCurrentVirtualDesktopId(reinterpret_cast<GUID*>(¤tDesktop)))
|
||||
{
|
||||
@@ -653,19 +683,18 @@ safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::Ter
|
||||
if (desktopId == currentDesktop && lastActivatedTime > max)
|
||||
{
|
||||
max = lastActivatedTime;
|
||||
mostRecentWeak = w;
|
||||
mostRecent = w;
|
||||
}
|
||||
}
|
||||
|
||||
// GetVirtualDesktopId(), as current implemented, should always return on the main thread.
|
||||
_assertIsMainThread();
|
||||
window = mostRecent.get();
|
||||
}
|
||||
|
||||
// GetVirtualDesktopId(), as current implemented, should always return on the main thread.
|
||||
_assertIsMainThread();
|
||||
|
||||
const auto mostRecent = mostRecentWeak.lock();
|
||||
auto window = mostRecent.get();
|
||||
|
||||
if (!window)
|
||||
else
|
||||
{
|
||||
// If virtual desktops have never been used, and in turn Explorer never set them up,
|
||||
// GetCurrentVirtualDesktopId will return false. In this case just use the current (only) desktop.
|
||||
window = _mostRecentWindow();
|
||||
}
|
||||
|
||||
@@ -681,6 +710,8 @@ safe_void_coroutine WindowEmperor::_dispatchCommandlineCurrentDesktop(winrt::Ter
|
||||
|
||||
bool WindowEmperor::_summonWindow(const SummonWindowSelectionArgs& args) const
|
||||
{
|
||||
_assertIsMainThread();
|
||||
|
||||
AppHost* window = nullptr;
|
||||
|
||||
if (args.WindowID)
|
||||
@@ -721,6 +752,8 @@ bool WindowEmperor::_summonWindow(const SummonWindowSelectionArgs& args) const
|
||||
|
||||
void WindowEmperor::_summonAllWindows() const
|
||||
{
|
||||
_assertIsMainThread();
|
||||
|
||||
TerminalApp::SummonWindowBehavior args;
|
||||
args.ToggleVisibility(false);
|
||||
|
||||
@@ -858,6 +891,9 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
||||
// Did the window counter get out of sync? It shouldn't.
|
||||
assert(_windowCount == gsl::narrow_cast<int32_t>(_windows.size()));
|
||||
|
||||
// !!! NOTE !!!
|
||||
// At least theoretically the lParam pointer may be invalid.
|
||||
// We should only access it if we find it in our _windows array.
|
||||
const auto host = reinterpret_cast<AppHost*>(lParam);
|
||||
auto it = _windows.begin();
|
||||
const auto end = _windows.end();
|
||||
@@ -866,8 +902,16 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
||||
{
|
||||
if (host == it->get())
|
||||
{
|
||||
host->Close();
|
||||
// NOTE: AppHost::Close is highly non-trivial.
|
||||
//
|
||||
// It _may_ call into XAML, which _may_ pump the message loop, which would then recursively
|
||||
// re-enter this function, which _may_ then handle another WM_CLOSE_TERMINAL_WINDOW,
|
||||
// which would change the _windows array, and invalidate our iterator and crash.
|
||||
//
|
||||
// We can prevent this by deferring Close() until after the erase() call.
|
||||
const auto strong = *it;
|
||||
_windows.erase(it);
|
||||
strong->Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +84,14 @@ private:
|
||||
int32_t _windowCount = 0;
|
||||
int32_t _messageBoxCount = 0;
|
||||
|
||||
#ifdef NDEBUG
|
||||
#if 0 // #ifdef NDEBUG
|
||||
static constexpr void _assertIsMainThread() noexcept
|
||||
{
|
||||
}
|
||||
#else
|
||||
void _assertIsMainThread() const noexcept
|
||||
{
|
||||
assert(_mainThreadId == GetCurrentThreadId());
|
||||
WI_ASSERT_MSG(_mainThreadId == GetCurrentThreadId(), "This part of WindowEmperor must be accessed from the UI thread");
|
||||
}
|
||||
DWORD _mainThreadId = GetCurrentThreadId();
|
||||
#endif
|
||||
|
||||
@@ -179,6 +179,9 @@ namespace Microsoft.Terminal.Wpf
|
||||
SWP_SHOWWINDOW = 0x0040,
|
||||
}
|
||||
|
||||
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
|
||||
public static extern void AvoidBuggyTSFConsoleFlags();
|
||||
|
||||
[DllImport("Microsoft.Terminal.Control.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, PreserveSig = false)]
|
||||
public static extern void CreateTerminal(IntPtr parent, out IntPtr hwnd, out IntPtr terminal);
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace Microsoft.Terminal.Wpf
|
||||
/// </summary>
|
||||
public TerminalContainer()
|
||||
{
|
||||
// WPF & TSF can't deal with us setting TF_TMAE_CONSOLE on the UI thread.
|
||||
// It simply crashes on Windows 10 if you use the Emoji picker.
|
||||
// (On later versions of Windows it just doesn't work.)
|
||||
NativeMethods.AvoidBuggyTSFConsoleFlags();
|
||||
|
||||
this.MessageHook += this.TerminalContainer_MessageHook;
|
||||
this.GotFocus += this.TerminalContainer_GotFocus;
|
||||
this.Focusable = true;
|
||||
|
||||
@@ -68,6 +68,13 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_AtlasEngineLoudErrors</name>
|
||||
<description>Atlas Engine can optionally support signaling every presentation failure to its consumer. For now, we only want that to happen in non-Release builds.</description>
|
||||
<stage>AlwaysEnabled</stage>
|
||||
<alwaysDisabledReleaseTokens/>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_NearbyFontLoading</name>
|
||||
<description>Controls whether fonts in the same directory as the binary are used during rendering. Disabled for conhost so that it doesn't iterate the entire system32 directory.</description>
|
||||
@@ -133,10 +140,14 @@
|
||||
<name>Feature_VtChecksumReport</name>
|
||||
<description>Enables the DECRQCRA checksum report, which can be used to read the screen contents</description>
|
||||
<id>14974</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
<stage>AlwaysEnabled</stage>
|
||||
<alwaysDisabledBrandingTokens>
|
||||
<!--
|
||||
Since we have a way to turn this on and off in Terminal, we don't need to hide it behind a feature
|
||||
flag any longer; however, conhost has no way to turn it off so let's just compile it out for now.
|
||||
-->
|
||||
<brandingToken>WindowsInbox</brandingToken>
|
||||
</alwaysDisabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
|
||||
@@ -170,7 +170,12 @@ void HandleGenericKeyEvent(INPUT_RECORD event, const bool generateBreak)
|
||||
|
||||
if (gci.HasActiveOutputBuffer())
|
||||
{
|
||||
gci.GetActiveOutputBuffer().SnapOnInput(keyEvent.wVirtualKeyCode);
|
||||
auto& buffer = gci.GetActiveOutputBuffer();
|
||||
|
||||
if (WI_IsFlagSet(buffer.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||
{
|
||||
buffer.SnapOnInput(keyEvent.wVirtualKeyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1718,6 +1718,19 @@ void SCREEN_INFORMATION::SnapOnInput(const WORD vkey)
|
||||
}
|
||||
}
|
||||
|
||||
SCREEN_INFORMATION::SnapOnScopeExit SCREEN_INFORMATION::SnapOnOutput() noexcept
|
||||
{
|
||||
const auto call =
|
||||
// We don't need to snap-on-output the alt buffer since it doesn't scroll anyway.
|
||||
// More importantly though, in the current architecture the alt buffer gets deallocated
|
||||
// the second we receive a \033[?1049l, which makes our this pointer hazardous to use.
|
||||
_psiMainBuffer == nullptr &&
|
||||
// We only want to snap if the user didn't intentionally scroll away.
|
||||
// The snapping logic could be improved, but it's alright for now.
|
||||
_viewport.IsInBounds(_textBuffer->GetCursor().GetPosition());
|
||||
return SnapOnScopeExit{ call ? this : nullptr };
|
||||
}
|
||||
|
||||
void SCREEN_INFORMATION::_makeCursorVisible()
|
||||
{
|
||||
if (_textBuffer->GetCursor().IsVisible())
|
||||
|
||||
@@ -50,6 +50,25 @@ class ConversionAreaInfo; // forward decl window. circular reference
|
||||
class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console::IIoProvider
|
||||
{
|
||||
public:
|
||||
// This little helper works like wil::scope_exit but is slimmer
|
||||
// (= easier to optimize) and has a concrete type (= can declare).
|
||||
struct SnapOnScopeExit
|
||||
{
|
||||
~SnapOnScopeExit()
|
||||
{
|
||||
if (self)
|
||||
{
|
||||
try
|
||||
{
|
||||
self->_makeCursorVisible();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
|
||||
SCREEN_INFORMATION* self;
|
||||
};
|
||||
|
||||
[[nodiscard]] static NTSTATUS CreateInstance(_In_ til::size coordWindowSize,
|
||||
const FontInfo fontInfo,
|
||||
_In_ til::size coordScreenBufferSize,
|
||||
@@ -73,16 +92,7 @@ public:
|
||||
void MakeCurrentCursorVisible();
|
||||
void MakeCursorVisible(til::point position);
|
||||
void SnapOnInput(WORD vkey);
|
||||
auto SnapOnOutput() noexcept
|
||||
{
|
||||
const auto inBounds = _viewport.IsInBounds(_textBuffer->GetCursor().GetPosition());
|
||||
return wil::scope_exit([this, inBounds]() {
|
||||
if (inBounds)
|
||||
{
|
||||
_makeCursorVisible();
|
||||
}
|
||||
});
|
||||
}
|
||||
SnapOnScopeExit SnapOnOutput() noexcept;
|
||||
|
||||
void ClipToScreenBuffer(_Inout_ til::inclusive_rect* const psrClip) const;
|
||||
|
||||
|
||||
@@ -366,12 +366,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
if (til::compare_ordinal_insensitive(var, temp) == 0 ||
|
||||
til::compare_ordinal_insensitive(var, tmp) == 0)
|
||||
{
|
||||
return til::details::wil_env::GetShortPathNameW<std::wstring, 256>(value.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::wstring{ value };
|
||||
std::wstring shortPath;
|
||||
if (SUCCEEDED((til::details::wil_env::GetShortPathNameW<std::wstring, 256>(value.data(), shortPath))))
|
||||
{
|
||||
return shortPath;
|
||||
}
|
||||
}
|
||||
return std::wstring{ value };
|
||||
}
|
||||
|
||||
static bool is_path_var(std::wstring_view input) noexcept
|
||||
|
||||
@@ -567,7 +567,7 @@ BOOL HandleMouseEvent(const SCREEN_INFORMATION& ScreenInfo,
|
||||
if (!fShiftPressed && !pSelection->IsInSelectingState())
|
||||
{
|
||||
short sDelta = 0;
|
||||
if (Message == WM_MOUSEWHEEL)
|
||||
if (Message == WM_MOUSEWHEEL || Message == WM_MOUSEHWHEEL)
|
||||
{
|
||||
sDelta = GET_WHEEL_DELTA_WPARAM(wParam);
|
||||
}
|
||||
|
||||
@@ -61,13 +61,18 @@ catch (const wil::ResultException& exception)
|
||||
return E_PENDING;
|
||||
}
|
||||
|
||||
if (_p.warningCallback)
|
||||
if constexpr (Feature_AtlasEngineLoudErrors::IsEnabled())
|
||||
{
|
||||
try
|
||||
// We may fail to present repeatedly, e.g. if there's a short-term device failure.
|
||||
// We should not bombard the consumer with repeated warning callbacks (where they may present a dialog to the user).
|
||||
if (_p.warningCallback)
|
||||
{
|
||||
_p.warningCallback(hr, {});
|
||||
try
|
||||
{
|
||||
_p.warningCallback(hr, {});
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
|
||||
_b.reset();
|
||||
|
||||
@@ -9,9 +9,10 @@ using namespace Microsoft::Console::Types;
|
||||
|
||||
using PointTree = interval_tree::IntervalTree<til::point, size_t>;
|
||||
|
||||
static constexpr auto maxRetriesForRenderEngine = 3;
|
||||
// The renderer will wait this number of milliseconds * how many tries have elapsed before trying again.
|
||||
static constexpr auto renderBackoffBaseTimeMilliseconds{ 150 };
|
||||
// We want there to be five retry periods; after the last one, we will mark the render as failed.
|
||||
static constexpr unsigned int maxRetriesForRenderEngine = 5;
|
||||
// The renderer will wait this number of milliseconds * 2^tries before trying again.
|
||||
static constexpr DWORD renderBackoffBaseTimeMilliseconds = 100;
|
||||
|
||||
#define FOREACH_ENGINE(var) \
|
||||
for (auto var : _engines) \
|
||||
@@ -44,40 +45,44 @@ IRenderData* Renderer::GetRenderData() const noexcept
|
||||
// - HRESULT S_OK, GDI error, Safe Math error, or state/argument errors.
|
||||
[[nodiscard]] HRESULT Renderer::PaintFrame()
|
||||
{
|
||||
auto tries = maxRetriesForRenderEngine;
|
||||
while (tries > 0)
|
||||
HRESULT hr{ S_FALSE };
|
||||
// Attempt zero doesn't count as a retry. We should try maxRetries + 1 times.
|
||||
for (unsigned int attempt = 0u; attempt <= maxRetriesForRenderEngine; ++attempt)
|
||||
{
|
||||
if (attempt > 0) [[unlikely]]
|
||||
{
|
||||
// Add a bit of backoff.
|
||||
// Sleep 100, 200, 400, 600, 800ms, 1600ms before failing out and disabling the renderer.
|
||||
Sleep(renderBackoffBaseTimeMilliseconds * (1 << (attempt - 1)));
|
||||
}
|
||||
|
||||
// BODGY: Optimally we would want to retry per engine, but that causes different
|
||||
// problems (intermittent inconsistent states between text renderer and UIA output,
|
||||
// not being able to lock the cursor location, etc.).
|
||||
const auto hr = _PaintFrame();
|
||||
hr = _PaintFrame();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_HR_IF(hr, hr != E_PENDING);
|
||||
|
||||
if (--tries == 0)
|
||||
{
|
||||
// Stop trying.
|
||||
_thread.DisablePainting();
|
||||
if (_pfnRendererEnteredErrorState)
|
||||
{
|
||||
_pfnRendererEnteredErrorState();
|
||||
}
|
||||
// If there's no callback, we still don't want to FAIL_FAST: the renderer going black
|
||||
// isn't near as bad as the entire application aborting. We're a component. We shouldn't
|
||||
// abort applications that host us.
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// Add a bit of backoff.
|
||||
// Sleep 150ms, 300ms, 450ms before failing out and disabling the renderer.
|
||||
Sleep(renderBackoffBaseTimeMilliseconds * (maxRetriesForRenderEngine - tries));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Stop trying.
|
||||
_thread.DisablePainting();
|
||||
if (_pfnRendererEnteredErrorState)
|
||||
{
|
||||
_pfnRendererEnteredErrorState();
|
||||
}
|
||||
// If there's no callback, we still don't want to FAIL_FAST: the renderer going black
|
||||
// isn't near as bad as the entire application aborting. We're a component. We shouldn't
|
||||
// abort applications that host us.
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT Renderer::_PaintFrame() noexcept
|
||||
|
||||
@@ -127,10 +127,13 @@ public:
|
||||
wch = L'!';
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
Log::Comment(NoThrowString().Format(L"MOUSEWHEEL"));
|
||||
wch = L'`' + (sScrollDelta > 0 ? 0 : 1);
|
||||
break;
|
||||
case WM_MOUSEHWHEEL:
|
||||
Log::Comment(NoThrowString().Format(L"MOUSEHWHEEL"));
|
||||
wch = L'b' + (sScrollDelta > 0 ? 1 : 0);
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
default:
|
||||
Log::Comment(NoThrowString().Format(L"DEFAULT"));
|
||||
@@ -168,9 +171,11 @@ public:
|
||||
result = 3 + 0x20; // we add 0x20 to hover events, which are all encoded as WM_MOUSEMOVE events
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
result = (sScrollDelta > 0 ? 64 : 65);
|
||||
break;
|
||||
case WM_MOUSEHWHEEL:
|
||||
result = (sScrollDelta > 0 ? 67 : 66);
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
@@ -582,6 +587,12 @@ public:
|
||||
Log::Comment(L"Test mouse wheel scrolling down");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1B[B"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling right");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1B[C"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEHWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling left");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1B[D"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEHWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Enable cursor keys mode");
|
||||
mouseInput.SetInputMode(TerminalInput::Mode::CursorKey, true);
|
||||
|
||||
@@ -591,6 +602,12 @@ public:
|
||||
Log::Comment(L"Test mouse wheel scrolling down");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1BOB"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling right");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1BOC"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEHWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling left");
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1BOD"), mouseInput.HandleMouse({ 0, 0 }, WM_MOUSEHWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Confirm no effect when scroll mode is disabled");
|
||||
mouseInput.UseAlternateScreenBuffer();
|
||||
mouseInput.SetInputMode(TerminalInput::Mode::AlternateScroll, false);
|
||||
|
||||
@@ -163,9 +163,11 @@ static constexpr wchar_t _windowsButtonToXEncoding(const unsigned int button,
|
||||
xvalue = 1;
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
xvalue = delta > 0 ? 0x40 : 0x41;
|
||||
break;
|
||||
case WM_MOUSEHWHEEL:
|
||||
xvalue = delta > 0 ? 0x43 : 0x42;
|
||||
break;
|
||||
default:
|
||||
xvalue = 0;
|
||||
break;
|
||||
@@ -221,9 +223,11 @@ static constexpr int _windowsButtonToSGREncoding(const unsigned int button,
|
||||
xvalue = 3;
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
xvalue = delta > 0 ? 0x40 : 0x41;
|
||||
break;
|
||||
case WM_MOUSEHWHEEL:
|
||||
xvalue = delta > 0 ? 0x43 : 0x42;
|
||||
break;
|
||||
default:
|
||||
xvalue = 0;
|
||||
break;
|
||||
@@ -378,7 +382,7 @@ TerminalInput::OutputType TerminalInput::HandleMouse(const til::point position,
|
||||
|
||||
if (ShouldSendAlternateScroll(button, delta))
|
||||
{
|
||||
return _makeAlternateScrollOutput(delta);
|
||||
return _makeAlternateScrollOutput(button, delta);
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -493,14 +497,32 @@ bool TerminalInput::ShouldSendAlternateScroll(const unsigned int button, const s
|
||||
// - Sends a sequence to the input corresponding to cursor up / down depending on the sScrollDelta.
|
||||
// Parameters:
|
||||
// - delta: The scroll wheel delta of the input event
|
||||
TerminalInput::OutputType TerminalInput::_makeAlternateScrollOutput(const short delta) const
|
||||
TerminalInput::OutputType TerminalInput::_makeAlternateScrollOutput(const unsigned int button, const short delta) const
|
||||
{
|
||||
if (delta > 0)
|
||||
if (button == WM_MOUSEWHEEL)
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_UP));
|
||||
if (delta > 0)
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_UP));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_DOWN));
|
||||
}
|
||||
}
|
||||
else if (button == WM_MOUSEHWHEEL)
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_RIGHT));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_LEFT));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_DOWN));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
[[nodiscard]] OutputType _GenerateUtf8Sequence(til::point position, unsigned int button, bool isHover, short modifierKeyState, short delta);
|
||||
[[nodiscard]] OutputType _GenerateSGRSequence(til::point position, unsigned int button, bool isRelease, bool isHover, short modifierKeyState, short delta);
|
||||
|
||||
[[nodiscard]] OutputType _makeAlternateScrollOutput(short delta) const;
|
||||
[[nodiscard]] OutputType _makeAlternateScrollOutput(unsigned int button, short delta) const;
|
||||
|
||||
static constexpr unsigned int s_GetPressedButton(const MouseButtonState state) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
@@ -897,6 +897,22 @@ bool InputStateMachineEngine::_UpdateSGRMouseButtonState(const VTID id,
|
||||
eventFlags |= MOUSE_WHEELED;
|
||||
break;
|
||||
}
|
||||
case CsiMouseButtonCodes::ScrollLeft:
|
||||
{
|
||||
// set high word to proper scroll direction
|
||||
// scroll intensity is assumed to be constant value
|
||||
buttonState |= SCROLL_DELTA_BACKWARD;
|
||||
eventFlags |= MOUSE_HWHEELED;
|
||||
break;
|
||||
}
|
||||
case CsiMouseButtonCodes::ScrollRight:
|
||||
{
|
||||
// set high word to proper scroll direction
|
||||
// scroll intensity is assumed to be constant value
|
||||
buttonState |= SCROLL_DELTA_FORWARD;
|
||||
eventFlags |= MOUSE_HWHEELED;
|
||||
break;
|
||||
}
|
||||
case CsiMouseButtonCodes::Released:
|
||||
// hover event, we still want to send these but we don't
|
||||
// need to do anything special here, so just break
|
||||
|
||||
@@ -111,6 +111,8 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
Released = 3,
|
||||
ScrollForward = 4,
|
||||
ScrollBack = 5,
|
||||
ScrollLeft = 6,
|
||||
ScrollRight = 7,
|
||||
};
|
||||
|
||||
constexpr unsigned short CsiMouseModifierCode_Drag = 32;
|
||||
|
||||
@@ -1194,8 +1194,10 @@ void InputEngineTest::SGRMouseTest_Scroll()
|
||||
// NOTE: scrolling events do NOT send a mouse up event
|
||||
const std::vector<std::tuple<SGR_PARAMS, MOUSE_EVENT_PARAMS>> testData = {
|
||||
// TEST INPUT EXPECTED OUTPUT
|
||||
{ { CsiMouseButtonCodes::ScrollForward, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_FORWARD, 0, { 0, 0 }, MOUSE_WHEELED } },
|
||||
{ { CsiMouseButtonCodes::ScrollBack, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_BACKWARD, 0, { 0, 0 }, MOUSE_WHEELED } },
|
||||
{ { CsiMouseButtonCodes::ScrollForward, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_FORWARD, 0, { 0, 0 }, MOUSE_WHEELED } },
|
||||
{ { CsiMouseButtonCodes::ScrollBack, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_BACKWARD, 0, { 0, 0 }, MOUSE_WHEELED } },
|
||||
{ { CsiMouseButtonCodes::ScrollLeft, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_BACKWARD, 0, { 0, 0 }, MOUSE_HWHEELED } },
|
||||
{ { CsiMouseButtonCodes::ScrollRight, 0, { 1, 1 }, CsiActionCodes::MouseDown }, { SCROLL_DELTA_FORWARD, 0, { 0, 0 }, MOUSE_HWHEELED } },
|
||||
};
|
||||
// clang-format on
|
||||
VerifySGRMouseData(testData);
|
||||
|
||||
@@ -12,10 +12,19 @@ Handle Handle::Create()
|
||||
{
|
||||
Handle handle;
|
||||
handle._impl = new Implementation();
|
||||
handle._impl->Initialize();
|
||||
if (!handle._impl->Initialize())
|
||||
{
|
||||
delete handle._impl;
|
||||
handle._impl = nullptr;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Handle::AvoidBuggyTSFConsoleFlags()
|
||||
{
|
||||
Implementation::AvoidBuggyTSFConsoleFlags();
|
||||
}
|
||||
|
||||
void Handle::SetDefaultScopeAlphanumericHalfWidth(bool enable)
|
||||
{
|
||||
Implementation::SetDefaultScopeAlphanumericHalfWidth(enable);
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace Microsoft::Console::TSF
|
||||
struct Handle
|
||||
{
|
||||
static Handle Create();
|
||||
static void AvoidBuggyTSFConsoleFlags();
|
||||
static void SetDefaultScopeAlphanumericHalfWidth(bool enable);
|
||||
|
||||
Handle() = default;
|
||||
|
||||
@@ -27,20 +27,61 @@ static void TfPropertyvalClose(TF_PROPERTYVAL* val)
|
||||
}
|
||||
using unique_tf_propertyval = wil::unique_struct<TF_PROPERTYVAL, decltype(&TfPropertyvalClose), &TfPropertyvalClose>;
|
||||
|
||||
void Implementation::SetDefaultScopeAlphanumericHalfWidth(bool enable) noexcept
|
||||
// The flags passed to ActivateEx don't replace the flags during previous calls.
|
||||
// Instead, they're additive. So, if we pass flags that some concurrently running
|
||||
// TSF clients don't expect we may blow them up accidentally.
|
||||
//
|
||||
// Such is the case with WPF (and TSF, which is actually at fault there).
|
||||
// If you pass TF_TMAE_CONSOLE it'll instantly crash on Windows 10 on first text input.
|
||||
// On Windows 11 it'll at least not crash but still make emoji input completely non-functional.
|
||||
//
|
||||
// --------
|
||||
//
|
||||
// In any case, we pass the same flags as conhost v1:
|
||||
// - TF_TMAE_UIELEMENTENABLEDONLY: TSF activates only text services that are
|
||||
// categorized in GUID_TFCAT_TIPCAP_UIELEMENTENABLED.
|
||||
// - TF_TMAE_NOACTIVATEKEYBOARDLAYOUT: TSF does not sync the current keyboard layout
|
||||
// while this method is called. The keyboard layout will be adjusted when the
|
||||
// calling thread gets focus. This flag must be used with TF_TMAE_NOACTIVATETIP.
|
||||
// - TF_TMAE_CONSOLE: A text service is activated for console usage.
|
||||
// Some IMEs are known to use this as a hint. Particularly a Korean IME can benefit
|
||||
// from this, because Korean relies on "recomposing" previously finished compositions.
|
||||
// That can't work in a terminal, since we submit composed text to the shell immediately.
|
||||
//
|
||||
// I'm not sure what TF_TMAE_UIELEMENTENABLEDONLY does. I tried to figure it out but failed.
|
||||
//
|
||||
// For TF_TMAE_NOACTIVATEKEYBOARDLAYOUT, I'm 99% sure it doesn't do anything, including in
|
||||
// conhost v1. This is because IMM will be initialized on WM_ACTIVATE, which calls ActivateEx(0).
|
||||
// Any subsequent ActivateEx() calls will update the flags, _except_ for this one and
|
||||
// TF_TMAE_NOACTIVATETIP which are explicitly filtered out.
|
||||
//
|
||||
// TF_TMAE_NOACTIVATETIP however is important. Without it, TIPs are immediately initialized.
|
||||
static std::atomic<DWORD> s_activationFlags{ TF_TMAE_NOACTIVATETIP | TF_TMAE_UIELEMENTENABLEDONLY | TF_TMAE_NOACTIVATEKEYBOARDLAYOUT | TF_TMAE_CONSOLE };
|
||||
void Implementation::AvoidBuggyTSFConsoleFlags() noexcept
|
||||
{
|
||||
_wantsAnsiInputScope.store(enable, std::memory_order_relaxed);
|
||||
s_activationFlags.fetch_and(~static_cast<DWORD>(TF_TMAE_CONSOLE), std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Implementation::Initialize()
|
||||
static std::atomic<bool> s_wantsAnsiInputScope{ false };
|
||||
void Implementation::SetDefaultScopeAlphanumericHalfWidth(bool enable) noexcept
|
||||
{
|
||||
_categoryMgr = wil::CoCreateInstance<ITfCategoryMgr>(CLSID_TF_CategoryMgr, CLSCTX_INPROC_SERVER);
|
||||
s_wantsAnsiInputScope.store(enable, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool Implementation::Initialize()
|
||||
{
|
||||
_categoryMgr = wil::CoCreateInstanceNoThrow<ITfCategoryMgr>(CLSID_TF_CategoryMgr);
|
||||
if (!_categoryMgr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_displayAttributeMgr = wil::CoCreateInstance<ITfDisplayAttributeMgr>(CLSID_TF_DisplayAttributeMgr);
|
||||
|
||||
// There's no point in calling TF_GetThreadMgr. ITfThreadMgr is a per-thread singleton.
|
||||
_threadMgrEx = wil::CoCreateInstance<ITfThreadMgrEx>(CLSID_TF_ThreadMgr, CLSCTX_INPROC_SERVER);
|
||||
|
||||
THROW_IF_FAILED(_threadMgrEx->ActivateEx(&_clientId, TF_TMAE_CONSOLE));
|
||||
THROW_IF_FAILED(_threadMgrEx->ActivateEx(&_clientId, s_activationFlags.load(std::memory_order_relaxed)));
|
||||
THROW_IF_FAILED(_threadMgrEx->CreateDocumentMgr(_documentMgr.addressof()));
|
||||
|
||||
TfEditCookie ecTextStore;
|
||||
@@ -53,6 +94,7 @@ void Implementation::Initialize()
|
||||
THROW_IF_FAILED(_contextSource->AdviseSink(IID_ITfTextEditSink, static_cast<ITfTextEditSink*>(this), &_cookieTextEditSink));
|
||||
|
||||
THROW_IF_FAILED(_documentMgr->Push(_context.get()));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Implementation::Uninitialize() noexcept
|
||||
@@ -319,7 +361,7 @@ STDMETHODIMP Implementation::GetWnd(HWND* phwnd) noexcept
|
||||
|
||||
STDMETHODIMP Implementation::GetAttribute(REFGUID rguidAttribute, VARIANT* pvarValue) noexcept
|
||||
{
|
||||
if (_wantsAnsiInputScope.load(std::memory_order_relaxed) && IsEqualGUID(rguidAttribute, GUID_PROP_INPUTSCOPE))
|
||||
if (s_wantsAnsiInputScope.load(std::memory_order_relaxed) && IsEqualGUID(rguidAttribute, GUID_PROP_INPUTSCOPE))
|
||||
{
|
||||
_ansiInputScope.AddRef();
|
||||
pvarValue->vt = VT_UNKNOWN;
|
||||
|
||||
@@ -16,11 +16,12 @@ namespace Microsoft::Console::TSF
|
||||
|
||||
struct Implementation : ITfContextOwner, ITfContextOwnerCompositionSink, ITfTextEditSink
|
||||
{
|
||||
static void AvoidBuggyTSFConsoleFlags() noexcept;
|
||||
static void SetDefaultScopeAlphanumericHalfWidth(bool enable) noexcept;
|
||||
|
||||
virtual ~Implementation() = default;
|
||||
|
||||
void Initialize();
|
||||
bool Initialize();
|
||||
void Uninitialize() noexcept;
|
||||
HWND FindWindowOfActiveTSF() noexcept;
|
||||
void AssociateFocus(IDataProvider* provider);
|
||||
@@ -129,6 +130,5 @@ namespace Microsoft::Console::TSF
|
||||
int _compositions = 0;
|
||||
|
||||
AnsiInputScope _ansiInputScope{ this };
|
||||
inline static std::atomic<bool> _wantsAnsiInputScope{ false };
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user