mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-17 15:36:35 +00:00
Compare commits
46 Commits
dev/cazamo
...
v1.24.1021
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeeb126ab3 | ||
|
|
1e70e182f2 | ||
|
|
48e2d93330 | ||
|
|
6ba10c13d6 | ||
|
|
51fd044bd2 | ||
|
|
633cd6e9dc | ||
|
|
a3d508a487 | ||
|
|
0d2e8cecd0 | ||
|
|
fb3971f681 | ||
|
|
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
|
||||
|
||||
10
.github/actions/spelling/expect/expect.txt
vendored
10
.github/actions/spelling/expect/expect.txt
vendored
@@ -141,6 +141,7 @@ BValue
|
||||
Cacafire
|
||||
CALLCONV
|
||||
CANDRABINDU
|
||||
CANTCALLOUT
|
||||
capslock
|
||||
CARETBLINKINGENABLED
|
||||
CARRIAGERETURN
|
||||
@@ -809,6 +810,7 @@ inclusivity
|
||||
INCONTEXT
|
||||
INFOEX
|
||||
inheritcursor
|
||||
ININPUTSYNCCALL
|
||||
INITCOMMONCONTROLSEX
|
||||
INITDIALOG
|
||||
INITGUID
|
||||
@@ -1061,6 +1063,7 @@ Mypair
|
||||
Myval
|
||||
NAMELENGTH
|
||||
namestream
|
||||
NCACTIVATE
|
||||
NCCALCSIZE
|
||||
NCCREATE
|
||||
NCLBUTTONDOWN
|
||||
@@ -1091,6 +1094,8 @@ NEXTLINE
|
||||
nfe
|
||||
NLSMODE
|
||||
NOACTIVATE
|
||||
NOACTIVATEKEYBOARDLAYOUT
|
||||
NOACTIVATETIP
|
||||
NOAPPLYNOW
|
||||
NOCLIP
|
||||
NOCOMM
|
||||
@@ -1505,7 +1510,6 @@ scrolllock
|
||||
scrolloffset
|
||||
SCROLLSCALE
|
||||
SCROLLSCREENBUFFER
|
||||
scursor
|
||||
sddl
|
||||
SDKDDK
|
||||
segfault
|
||||
@@ -1703,9 +1707,11 @@ TEXTMETRIC
|
||||
TEXTMETRICW
|
||||
textmode
|
||||
texttests
|
||||
TFCAT
|
||||
THUMBPOSITION
|
||||
THUMBTRACK
|
||||
tilunittests
|
||||
TIPCAP
|
||||
titlebars
|
||||
TITLEISLINKNAME
|
||||
TLDP
|
||||
@@ -1757,6 +1763,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": [
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"PackageContents/WindowsTerminalShellExt.dll",
|
||||
|
||||
// The rest
|
||||
"PackageContents/TerminalAzBridge.exe",
|
||||
"PackageContents/wt.exe",
|
||||
"PackageContents/WindowsTerminal.exe",
|
||||
"PackageContents/elevate-shim.exe"
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -77,9 +77,6 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj">
|
||||
<Project>{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalAzBridge\TerminalAzBridge.vcxproj">
|
||||
<Project>{067F0A06-FCB7-472C-96E9-B03B54E8E18D}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj">
|
||||
<Project>{f2ed628a-db22-446f-a081-4cc845b51a2b}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
@@ -900,7 +900,10 @@ namespace winrt::TerminalApp::implementation
|
||||
co_return;
|
||||
}
|
||||
|
||||
// Hop to the BG thread
|
||||
// ShellExecuteExW may block, so do it on a background thread.
|
||||
//
|
||||
// NOTE: All remaining code of this function doesn't touch `this`, so we don't need weak/strong_ref.
|
||||
// NOTE NOTE: Don't touch `this` when you make changes here.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// This will get us the correct exe for dev/preview/release. If you
|
||||
@@ -1453,6 +1456,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
safe_void_coroutine TerminalPage::_doHandleSuggestions(SuggestionsArgs realArgs)
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
const auto dispatcher = Dispatcher();
|
||||
const auto source = realArgs.Source();
|
||||
std::vector<Command> commandsCollection;
|
||||
Control::CommandHistoryContext context{ nullptr };
|
||||
@@ -1519,7 +1524,12 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// Open the palette with all these commands in it.
|
||||
_OpenSuggestions(_GetActiveControl(),
|
||||
|
||||
@@ -150,7 +150,9 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
|
||||
_languageProfileNotifier = winrt::make_self<LanguageProfileNotifier>([this]() {
|
||||
_reloadSettings->Run();
|
||||
// TODO: This is really bad, because we reset any current user customizations.
|
||||
// See GH#11522.
|
||||
ReloadSettingsThrottled();
|
||||
});
|
||||
|
||||
// Do this here, rather than at the top of main. This will prevent us from
|
||||
@@ -330,7 +332,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (modifiedBasename == settingsBasename)
|
||||
{
|
||||
_reloadSettings->Run();
|
||||
ReloadSettingsThrottled();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -436,6 +438,11 @@ namespace winrt::TerminalApp::implementation
|
||||
SettingsChanged.raise(*this, *ev);
|
||||
}
|
||||
|
||||
void AppLogic::ReloadSettingsThrottled()
|
||||
{
|
||||
_reloadSettings->Run();
|
||||
}
|
||||
|
||||
// This is a continuation of AppLogic::Create() and includes the more expensive parts.
|
||||
void AppLogic::NotifyRootInitialized()
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool IsRunningElevated() const noexcept;
|
||||
bool CanDragDrop() const noexcept;
|
||||
void ReloadSettings();
|
||||
void ReloadSettingsThrottled();
|
||||
void NotifyRootInitialized();
|
||||
|
||||
bool HasSettingsStartupActions() const noexcept;
|
||||
@@ -80,7 +81,6 @@ namespace winrt::TerminalApp::implementation
|
||||
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
|
||||
void _ProcessLazySettingsChanges();
|
||||
void _RegisterSettingsChange();
|
||||
safe_void_coroutine _DispatchReloadSettings();
|
||||
|
||||
void _setupFolderPathEnvVar();
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace TerminalApp
|
||||
Boolean HasSettingsStartupActions();
|
||||
|
||||
void ReloadSettings();
|
||||
void ReloadSettingsThrottled();
|
||||
Microsoft.Terminal.Settings.Model.CascadiaSettings Settings { get; };
|
||||
|
||||
TerminalWindow CreateNewWindow();
|
||||
|
||||
@@ -34,9 +34,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
// before actually starting the connection to the client app. This
|
||||
// will ensure both controls are initialized before the client app
|
||||
// is.
|
||||
const auto weak = get_weak();
|
||||
co_await winrt::resume_background();
|
||||
_pairedTap->_start.wait();
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
_pairedTap->_start.wait();
|
||||
_wrappedConnection.Start();
|
||||
}
|
||||
void WriteInput(const winrt::array_view<const char16_t> buffer)
|
||||
|
||||
@@ -43,6 +43,9 @@ safe_void_coroutine Jumplist::UpdateJumplist(const CascadiaSettings& settings) n
|
||||
// make sure to capture the settings _before_ the co_await
|
||||
const auto strongSettings = settings;
|
||||
|
||||
// Explorer APIs may block, so do it on a background thread.
|
||||
//
|
||||
// NOTE: Jumplist has no members, so we don't need to hold onto `this` here.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
try
|
||||
|
||||
@@ -89,6 +89,18 @@ namespace winrt::TerminalApp::implementation
|
||||
CloseClick.raise(*this, e);
|
||||
}
|
||||
|
||||
bool MinMaxCloseControl::Focused() const
|
||||
{
|
||||
return _focused;
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::Focused(bool focused)
|
||||
{
|
||||
_focused = focused;
|
||||
|
||||
ReleaseButtons();
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::SetWindowVisualState(WindowVisualState visualState)
|
||||
{
|
||||
// Look up the heights we should use for the caption buttons from our
|
||||
@@ -170,25 +182,25 @@ namespace winrt::TerminalApp::implementation
|
||||
// animate the fade in/out transition between colors.
|
||||
case CaptionButton::Minimize:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
|
||||
|
||||
_displayToolTip->Run(MinimizeButton());
|
||||
closeToolTipForButton(MaximizeButton());
|
||||
closeToolTipForButton(CloseButton());
|
||||
break;
|
||||
case CaptionButton::Maximize:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
|
||||
|
||||
closeToolTipForButton(MinimizeButton());
|
||||
_displayToolTip->Run(MaximizeButton());
|
||||
closeToolTipForButton(CloseButton());
|
||||
break;
|
||||
case CaptionButton::Close:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"PointerOver", true);
|
||||
|
||||
closeToolTipForButton(MinimizeButton());
|
||||
@@ -211,17 +223,17 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
case CaptionButton::Minimize:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Pressed", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
|
||||
break;
|
||||
case CaptionButton::Maximize:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Pressed", true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
|
||||
break;
|
||||
case CaptionButton::Close:
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Pressed", true);
|
||||
break;
|
||||
}
|
||||
@@ -234,9 +246,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void MinMaxCloseControl::ReleaseButtons()
|
||||
{
|
||||
_displayToolTip->Run(nullptr);
|
||||
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
|
||||
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
|
||||
|
||||
closeToolTipForButton(MinimizeButton());
|
||||
closeToolTipForButton(MaximizeButton());
|
||||
@@ -244,4 +256,11 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
_lastPressedButton = std::nullopt;
|
||||
}
|
||||
|
||||
const winrt::param::hstring& MinMaxCloseControl::_normalState() const
|
||||
{
|
||||
static const winrt::param::hstring normal = L"Normal";
|
||||
static const winrt::param::hstring unfocused = L"Unfocused";
|
||||
return (_focused ? normal : unfocused);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void PressButton(CaptionButton button);
|
||||
void ReleaseButtons();
|
||||
|
||||
bool Focused() const;
|
||||
void Focused(bool focused);
|
||||
|
||||
void _MinimizeClick(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void _MaximizeClick(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
@@ -32,8 +35,12 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
|
||||
|
||||
bool _focused{ false };
|
||||
std::shared_ptr<ThrottledFunc<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
|
||||
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
|
||||
|
||||
private:
|
||||
const winrt::param::hstring& _normalState() const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace TerminalApp
|
||||
void HoverButton(CaptionButton button);
|
||||
void PressButton(CaptionButton button);
|
||||
void ReleaseButtons();
|
||||
Boolean Focused { get; set; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
|
||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
|
||||
ResourceKey="TextFillColorDisabled" />
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
|
||||
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
@@ -66,6 +70,10 @@
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundPressed"
|
||||
ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
|
||||
ResourceKey="TextFillColorDisabled" />
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
|
||||
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonBackground"
|
||||
Color="Transparent" />
|
||||
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
|
||||
@@ -103,6 +111,10 @@
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundPressed"
|
||||
Color="{ThemeResource SystemColorHighlightTextColor}" />
|
||||
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
|
||||
Color="{ThemeResource SystemColorButtonTextColor}" />
|
||||
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
|
||||
ResourceKey="SystemColorButtonTextColor" />
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
|
||||
Color="{ThemeResource SystemColorHighlightColor}" />
|
||||
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
|
||||
@@ -189,6 +201,20 @@
|
||||
Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
|
||||
<VisualTransition From="PointerOver"
|
||||
To="Unfocused">
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetName="ButtonBaseElement"
|
||||
Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonBackgroundColor}"
|
||||
Duration="0:0:0.15" />
|
||||
<ColorAnimation Storyboard.TargetName="ButtonIcon"
|
||||
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
|
||||
To="{ThemeResource CaptionButtonForegroundUnfocusedColor}"
|
||||
Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
|
||||
<VisualState x:Name="Normal">
|
||||
@@ -198,6 +224,13 @@
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Unfocused">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackground}" />
|
||||
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundUnfocused}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -48,13 +48,22 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_settings = settings;
|
||||
|
||||
const auto dispatcher = Dispatcher();
|
||||
const auto weak = get_weak();
|
||||
|
||||
// You'd think that `FilterToSendInput(queryString)` would work. It
|
||||
// doesn't! That uses the queryString as the current command the user
|
||||
// has typed, then relies on the suggestions UI to _also_ filter with that
|
||||
// string.
|
||||
|
||||
const auto tasks = co_await _settings.GlobalSettings().ActionMap().FilterToSnippets(winrt::hstring{}, winrt::hstring{}); // IVector<Model::Command>
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
_allTasks.Clear();
|
||||
for (const auto& t : tasks)
|
||||
|
||||
@@ -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*/) {
|
||||
@@ -402,12 +397,18 @@ namespace winrt::TerminalApp::implementation
|
||||
// - tab: the tab to remove
|
||||
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab)
|
||||
{
|
||||
winrt::com_ptr<TerminalPage> strong;
|
||||
|
||||
if (tab.ReadOnly())
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
|
||||
auto warningResult = co_await _ShowCloseReadOnlyDialog();
|
||||
|
||||
strong = weak.get();
|
||||
|
||||
// If the user didn't explicitly click on close tab - leave
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
if (!strong || warningResult != ContentDialogResult::Primary)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
@@ -664,7 +665,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() };
|
||||
@@ -718,10 +719,14 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (pane->ContainsReadOnly())
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
|
||||
auto warningResult = co_await _ShowCloseReadOnlyDialog();
|
||||
|
||||
const auto strong = weak.get();
|
||||
|
||||
// If the user didn't explicitly click on close tab - leave
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
if (!strong || warningResult != ContentDialogResult::Primary)
|
||||
{
|
||||
co_return false;
|
||||
}
|
||||
@@ -779,9 +784,13 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (const auto pane{ activeTab->GetActivePane() })
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
if (co_await _PaneConfirmCloseReadOnly(pane))
|
||||
{
|
||||
_HandleClosePaneRequested(pane);
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
_HandleClosePaneRequested(pane);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -839,9 +848,22 @@ namespace winrt::TerminalApp::implementation
|
||||
// - tabs - tabs to remove
|
||||
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs)
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
|
||||
for (auto& tab : tabs)
|
||||
{
|
||||
co_await _HandleCloseTabRequested(tab);
|
||||
winrt::Windows::Foundation::IAsyncAction action{ nullptr };
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
action = _HandleCloseTabRequested(tab);
|
||||
}
|
||||
|
||||
if (!action)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
co_await action;
|
||||
}
|
||||
}
|
||||
// Method Description:
|
||||
@@ -876,60 +898,69 @@ 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())
|
||||
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
|
||||
// `TabViewItem` that still contains a `Tab` which has actually already been removed.
|
||||
// First we must yield once, to flush out whatever TabView is currently doing.
|
||||
const auto weak = get_weak();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
_tabPointerMiddleButtonPressed = false;
|
||||
if (auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
{
|
||||
tabViewItem.ReleasePointerCapture(eventArgs.Pointer());
|
||||
if (!_tabPointerMiddleButtonExited)
|
||||
{
|
||||
_OnTabPointerReleasedCloseTab(std::move(tabViewItem));
|
||||
}
|
||||
}
|
||||
eventArgs.Handled(true);
|
||||
co_return;
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender)
|
||||
{
|
||||
const auto tab = _GetTabByTabViewItem(sender);
|
||||
if (!tab)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
|
||||
// `TabViewItem` that still contains a `Tab` which has actually already been removed.
|
||||
// First we must yield once, to flush out whatever TabView is currently doing.
|
||||
const auto strong = get_strong();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
// `tab.Shutdown()` in `_RemoveTab()` sets the content to null = This checks if the tab is closed.
|
||||
if (tab.Content())
|
||||
{
|
||||
@@ -937,34 +968,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.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <LibraryResources.h>
|
||||
#include <TerminalThemeHelpers.h>
|
||||
#include <til/unicode.h>
|
||||
#include <Utils.h>
|
||||
#include <TerminalCore/ControlKeyStates.hpp>
|
||||
|
||||
@@ -60,8 +61,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 +115,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 +384,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:
|
||||
@@ -1448,18 +1490,8 @@ namespace winrt::TerminalApp::implementation
|
||||
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
||||
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
||||
{
|
||||
std::filesystem::path azBridgePath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
azBridgePath.replace_filename(L"TerminalAzBridge.exe");
|
||||
if constexpr (Feature_AzureConnectionInProc::IsEnabled())
|
||||
{
|
||||
connection = TerminalConnection::AzureConnection{};
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = TerminalConnection::ConptyConnection{};
|
||||
}
|
||||
|
||||
valueSet = TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.native(),
|
||||
connection = TerminalConnection::AzureConnection{};
|
||||
valueSet = TerminalConnection::ConptyConnection::CreateSettings(winrt::hstring{},
|
||||
L".",
|
||||
L"Azure",
|
||||
false,
|
||||
@@ -2174,7 +2206,15 @@ namespace winrt::TerminalApp::implementation
|
||||
if (!_displayingCloseDialog)
|
||||
{
|
||||
_displayingCloseDialog = true;
|
||||
|
||||
const auto weak = get_weak();
|
||||
auto warningResult = co_await _ShowQuitDialog();
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
_displayingCloseDialog = false;
|
||||
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
@@ -2941,7 +2981,19 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// We have to initialize the dialog here to be able to change the text of the text block within it
|
||||
std::ignore = FindName(L"MultiLinePasteDialog");
|
||||
ClipboardText().Text(text);
|
||||
|
||||
// WinUI absolutely cannot deal with large amounts of text (at least O(n), possibly O(n^2),
|
||||
// so we limit the string length here and add an ellipsis if necessary.
|
||||
auto clipboardText = text;
|
||||
if (clipboardText.size() > 1024)
|
||||
{
|
||||
const std::wstring_view view{ text };
|
||||
// Make sure we don't cut in the middle of a surrogate pair
|
||||
const auto len = til::utf16_iterate_prev(view, 512);
|
||||
clipboardText = til::hstring_format(FMT_COMPILE(L"{}\n…"), view.substr(0, len));
|
||||
}
|
||||
|
||||
ClipboardText().Text(std::move(clipboardText));
|
||||
|
||||
// The vertical offset on the scrollbar does not reset automatically, so reset it manually
|
||||
ClipboardContentScrollViewer().ScrollToVerticalOffset(0);
|
||||
@@ -2957,7 +3009,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Clear the clipboard text so it doesn't lie around in memory
|
||||
ClipboardText().Text(L"");
|
||||
ClipboardText().Text({});
|
||||
|
||||
if (warningResult != ContentDialogResult::Primary)
|
||||
{
|
||||
@@ -3137,8 +3189,12 @@ namespace winrt::TerminalApp::implementation
|
||||
// - eventArgs: the arguments specifying how to set the progress indicator
|
||||
safe_void_coroutine TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
SetTaskbarProgress.raise(*this, nullptr);
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
SetTaskbarProgress.raise(*this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -3175,33 +3231,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;
|
||||
}
|
||||
|
||||
@@ -3211,6 +3251,12 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto weak = get_weak();
|
||||
const auto dispatcher = Dispatcher();
|
||||
|
||||
// All of the code until resume_foreground is static and
|
||||
// doesn't touch `this`, so we don't need weak/strong_ref.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// no packages were found, nothing to suggest
|
||||
@@ -3228,7 +3274,12 @@ namespace winrt::TerminalApp::implementation
|
||||
suggestions.emplace_back(fmt::format(FMT_COMPILE(L"winget install --id {} -s winget"), pkg.CatalogPackage().Id()));
|
||||
}
|
||||
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
co_await wil::resume_foreground(dispatcher);
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto term = _GetActiveControl();
|
||||
if (!term)
|
||||
@@ -3323,6 +3374,9 @@ namespace winrt::TerminalApp::implementation
|
||||
// UI) thread. This is IMPORTANT, because the Windows.Storage API's
|
||||
// (used for retrieving the path to the file) will crash on the UI
|
||||
// thread, because the main thread is a STA.
|
||||
//
|
||||
// NOTE: All remaining code of this function doesn't touch `this`, so we don't need weak/strong_ref.
|
||||
// NOTE NOTE: Don't touch `this` when you make changes here.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
auto openFile = [](const auto& filePath) {
|
||||
@@ -3808,6 +3862,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);
|
||||
@@ -4679,12 +4735,18 @@ namespace winrt::TerminalApp::implementation
|
||||
// - sender: the ICoreState instance containing the connection state
|
||||
// Return Value:
|
||||
// - <none>
|
||||
safe_void_coroutine TerminalPage::_ConnectionStateChangedHandler(const IInspectable& sender, const IInspectable& /*args*/) const
|
||||
safe_void_coroutine TerminalPage::_ConnectionStateChangedHandler(const IInspectable& sender, const IInspectable& /*args*/)
|
||||
{
|
||||
if (const auto coreState{ sender.try_as<winrt::Microsoft::Terminal::Control::ICoreState>() })
|
||||
{
|
||||
const auto newConnectionState = coreState.ConnectionState();
|
||||
const auto weak = get_weak();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
_adjustProcessPriorityThrottled->Run();
|
||||
|
||||
@@ -4822,8 +4884,18 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// GH#19604: Get the theme's tabRow color to use as the acrylic tint.
|
||||
const auto tabRowBg{ theme.TabRow() ? (_activated ? theme.TabRow().Background() :
|
||||
theme.TabRow().UnfocusedBackground()) :
|
||||
ThemeColor{ nullptr } };
|
||||
|
||||
if (_settings.GlobalSettings().UseAcrylicInTabRow())
|
||||
{
|
||||
if (tabRowBg)
|
||||
{
|
||||
bgColor = ThemeColor::ColorFromBrush(tabRowBg.Evaluate(res, terminalBrush, true));
|
||||
}
|
||||
|
||||
const auto acrylicBrush = Media::AcrylicBrush();
|
||||
acrylicBrush.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
|
||||
acrylicBrush.FallbackColor(bgColor);
|
||||
@@ -4832,9 +4904,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
TitlebarBrush(acrylicBrush);
|
||||
}
|
||||
else if (auto tabRowBg{ theme.TabRow() ? (_activated ? theme.TabRow().Background() :
|
||||
theme.TabRow().UnfocusedBackground()) :
|
||||
ThemeColor{ nullptr } })
|
||||
else if (tabRowBg)
|
||||
{
|
||||
const auto themeBrush{ tabRowBg.Evaluate(res, terminalBrush, true) };
|
||||
bgColor = ThemeColor::ColorFromBrush(themeBrush);
|
||||
|
||||
@@ -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);
|
||||
@@ -515,7 +520,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
void _OpenElevatedWT(winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
|
||||
|
||||
safe_void_coroutine _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
safe_void_coroutine _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
||||
@@ -531,7 +536,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
Windows::Foundation::IAsyncAction _SearchMissingCommandHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::SearchMissingCommandEventArgs args);
|
||||
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::MatchResult>> _FindPackageAsync(hstring query);
|
||||
static Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::MatchResult>> _FindPackageAsync(hstring query);
|
||||
|
||||
void _WindowSizeChanged(const IInspectable sender, const winrt::Microsoft::Terminal::Control::WindowSizeChangedEventArgs args);
|
||||
void _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -322,6 +322,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// - an IAsyncOperation with the dialog result
|
||||
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalWindow::ShowDialog(winrt::WUX::Controls::ContentDialog dialog)
|
||||
{
|
||||
const auto weak = get_weak();
|
||||
const auto dispatcher = _root->Dispatcher();
|
||||
const auto root = _root->XamlRoot();
|
||||
|
||||
// As mentioned on s_activeDialog, dismissing the active dialog is necessary.
|
||||
// We repeat it a few times in case the resume_foreground failed to work,
|
||||
// but I found that one iteration will always be enough in practice.
|
||||
@@ -335,7 +339,7 @@ namespace winrt::TerminalApp::implementation
|
||||
s_activeDialog.Hide();
|
||||
|
||||
// Wait for the current dialog to be hidden.
|
||||
co_await wil::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Low);
|
||||
co_await wil::resume_foreground(dispatcher, CoreDispatcherPriority::Low);
|
||||
}
|
||||
|
||||
// If two sources call ShowDialog() simultaneously, it may happen that both enter the above loop,
|
||||
@@ -352,7 +356,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
|
||||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
|
||||
// xaml tree somehow.
|
||||
dialog.XamlRoot(_root->XamlRoot());
|
||||
dialog.XamlRoot(root);
|
||||
|
||||
// IMPORTANT: Set the requested theme of the dialog, because the
|
||||
// PopupRoot isn't directly in the Xaml tree of our root. So the dialog
|
||||
@@ -366,14 +370,17 @@ namespace winrt::TerminalApp::implementation
|
||||
// theme on each element up to the root. We're relying a bit on Xaml's implementation
|
||||
// details here, but it does have the desired effect.
|
||||
// It's not enough to set the theme on the dialog alone.
|
||||
auto themingLambda{ [this](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
|
||||
auto theme{ _settings.GlobalSettings().CurrentTheme() };
|
||||
auto requestedTheme{ theme.RequestedTheme() };
|
||||
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
|
||||
while (element)
|
||||
auto themingLambda{ [weak](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
element.RequestedTheme(requestedTheme);
|
||||
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
|
||||
auto theme{ strong->_settings.GlobalSettings().CurrentTheme() };
|
||||
auto requestedTheme{ theme.RequestedTheme() };
|
||||
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
|
||||
while (element)
|
||||
{
|
||||
element.RequestedTheme(requestedTheme);
|
||||
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
|
||||
}
|
||||
}
|
||||
} };
|
||||
|
||||
@@ -888,6 +895,11 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Manually bubble the OnDirectKeyEvent event up through the focus tree.
|
||||
auto xamlRoot{ _root->XamlRoot() };
|
||||
if (!xamlRoot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto focusedObject{ Windows::UI::Xaml::Input::FocusManager::GetFocusedElement(xamlRoot) };
|
||||
do
|
||||
{
|
||||
@@ -1048,6 +1060,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;
|
||||
|
||||
@@ -53,6 +53,16 @@ namespace winrt::TerminalApp::implementation
|
||||
return static_cast<float>(minMaxCloseWidth) / 3.0f;
|
||||
}
|
||||
|
||||
bool TitlebarControl::Focused()
|
||||
{
|
||||
return MinMaxCloseControl().Focused();
|
||||
}
|
||||
|
||||
void TitlebarControl::Focused(bool focused)
|
||||
{
|
||||
MinMaxCloseControl().Focused(focused);
|
||||
}
|
||||
|
||||
IInspectable TitlebarControl::Content()
|
||||
{
|
||||
return ContentRoot().Content();
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void ReleaseButtons();
|
||||
float CaptionButtonWidth();
|
||||
|
||||
bool Focused();
|
||||
void Focused(bool focused);
|
||||
|
||||
IInspectable Content();
|
||||
void Content(IInspectable content);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace TerminalApp
|
||||
void ClickButton(CaptionButton button);
|
||||
void ReleaseButtons();
|
||||
Single CaptionButtonWidth { get; };
|
||||
Boolean Focused { get; set; };
|
||||
|
||||
IInspectable Content;
|
||||
Windows.UI.Xaml.Controls.Border DragBar { get; };
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ConsoleInputReader.h"
|
||||
#include "unicode.hpp"
|
||||
|
||||
ConsoleInputReader::ConsoleInputReader(HANDLE handle) :
|
||||
_handle(handle)
|
||||
{
|
||||
_buffer.resize(BufferSize);
|
||||
_convertedString.reserve(BufferSize);
|
||||
}
|
||||
|
||||
void ConsoleInputReader::SetWindowSizeChangedCallback(std::function<void()> callback)
|
||||
{
|
||||
_windowSizeChangedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
std::optional<std::wstring_view> ConsoleInputReader::Read()
|
||||
{
|
||||
DWORD readCount{ 0 };
|
||||
|
||||
_convertedString.clear();
|
||||
while (_convertedString.empty())
|
||||
{
|
||||
_buffer.resize(BufferSize);
|
||||
auto succeeded =
|
||||
ReadConsoleInputW(_handle, _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &readCount);
|
||||
if (!succeeded)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
_buffer.resize(readCount);
|
||||
for (auto it = _buffer.begin(); it != _buffer.end(); ++it)
|
||||
{
|
||||
if (it->EventType == WINDOW_BUFFER_SIZE_EVENT && _windowSizeChangedCallback)
|
||||
{
|
||||
_windowSizeChangedCallback();
|
||||
}
|
||||
else if (it->EventType == KEY_EVENT)
|
||||
{
|
||||
const auto& keyEvent = it->Event.KeyEvent;
|
||||
if (keyEvent.bKeyDown || (!keyEvent.bKeyDown && keyEvent.wVirtualKeyCode == VK_MENU))
|
||||
{
|
||||
// Got a high surrogate at the end of the buffer
|
||||
if (IS_HIGH_SURROGATE(keyEvent.uChar.UnicodeChar))
|
||||
{
|
||||
_highSurrogate.emplace(keyEvent.uChar.UnicodeChar);
|
||||
continue; // we've consumed it -- only dispatch it if we get a low
|
||||
}
|
||||
|
||||
if (IS_LOW_SURROGATE(keyEvent.uChar.UnicodeChar))
|
||||
{
|
||||
// No matter what we do, we want to destructively consume the high surrogate
|
||||
if (const auto oldHighSurrogate{ std::exchange(_highSurrogate, std::nullopt) })
|
||||
{
|
||||
_convertedString.push_back(*_highSurrogate);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we get a low without a high surrogate, we've done everything we can.
|
||||
// This is an illegal state.
|
||||
_convertedString.push_back(UNICODE_REPLACEMENT);
|
||||
continue; // onto the next event
|
||||
}
|
||||
}
|
||||
|
||||
// (\0 with a scancode is probably a modifier key, not a VT input key)
|
||||
if (keyEvent.uChar.UnicodeChar != L'\0' || keyEvent.wVirtualScanCode == 0)
|
||||
{
|
||||
if (_highSurrogate) // non-destructive: we don't want to set it to nullopt needlessly for every character
|
||||
{
|
||||
// If we get a high surrogate *here*, we didn't find a low surrogate.
|
||||
// This state is also illegal.
|
||||
_convertedString.push_back(UNICODE_REPLACEMENT);
|
||||
_highSurrogate.reset();
|
||||
}
|
||||
_convertedString.push_back(keyEvent.uChar.UnicodeChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _convertedString;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*++
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
|
||||
ConsoleInputReader.h
|
||||
|
||||
Abstract:
|
||||
|
||||
This file contains a class whose sole purpose is to
|
||||
abstract away a bunch of details you usually need to
|
||||
know to read VT from a console input handle.
|
||||
|
||||
--*/
|
||||
|
||||
class ConsoleInputReader
|
||||
{
|
||||
public:
|
||||
explicit ConsoleInputReader(HANDLE handle);
|
||||
void SetWindowSizeChangedCallback(std::function<void()> callback);
|
||||
std::optional<std::wstring_view> Read();
|
||||
|
||||
private:
|
||||
static constexpr size_t BufferSize{ 128 };
|
||||
|
||||
HANDLE _handle;
|
||||
std::wstring _convertedString;
|
||||
std::vector<INPUT_RECORD> _buffer;
|
||||
std::optional<wchar_t> _highSurrogate;
|
||||
std::function<void()> _windowSizeChangedCallback;
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{067F0A06-FCB7-472C-96E9-B03B54E8E18D}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>TerminalAzBridge</RootNamespace>
|
||||
<ProjectName>TerminalAzBridge</ProjectName>
|
||||
<TargetName>TerminalAzBridge</TargetName>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
|
||||
<VersionInfoFileDescription>Windows Terminal Azure Cloud Shell Connector</VersionInfoFileDescription>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="NuGet Dependencies">
|
||||
<TerminalCppWinrt>true</TerminalCppWinrt>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<GenerateManifest>true</GenerateManifest>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Source Files -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="ConsoleInputReader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="ConsoleInputReader.cpp" />
|
||||
</ItemGroup>
|
||||
<!-- Dependencies -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj">
|
||||
<Project>{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
This ItemGroup and the Globals PropertyGroup below it are required in order
|
||||
to enable F5 debugging for the unpackaged application
|
||||
-->
|
||||
<ItemGroup>
|
||||
<PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\debugger_general.xml" />
|
||||
<PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\debugger_local_windows.xml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<!-- These have to come after post.props because the Cpp common targets will inexplicably overwrite them. -->
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!--
|
||||
BODGY
|
||||
|
||||
The wapproj `GetResolvedWinMD` target tries to get a winmd from every cppwinrt
|
||||
executable we put in the package. But we DON'T produce a winmd. This makes the
|
||||
FastUpToDate check fail every time, and leads to the whole wapproj build
|
||||
running even if you're just f5'ing the package. EVEN AFTER A SUCCESSFUL BUILD.
|
||||
|
||||
Setting GenerateWindowsMetadata=false is enough to tell the build system that
|
||||
we don't produce one, and get it off our backs.
|
||||
-->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
|
||||
</Project>
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "winrt/Microsoft.Terminal.TerminalConnection.h"
|
||||
#include "ConsoleInputReader.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
|
||||
static til::size GetConsoleScreenSize(HANDLE outputHandle)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX csbiex{};
|
||||
csbiex.cbSize = sizeof(csbiex);
|
||||
GetConsoleScreenBufferInfoEx(outputHandle, &csbiex);
|
||||
return {
|
||||
(csbiex.srWindow.Right - csbiex.srWindow.Left) + 1,
|
||||
(csbiex.srWindow.Bottom - csbiex.srWindow.Top) + 1
|
||||
};
|
||||
}
|
||||
|
||||
static ConnectionState RunConnectionToCompletion(const ITerminalConnection& connection, HANDLE outputHandle, HANDLE inputHandle)
|
||||
{
|
||||
connection.TerminalOutput([outputHandle](const winrt::hstring& output) {
|
||||
WriteConsoleW(outputHandle, output.data(), output.size(), nullptr, nullptr);
|
||||
});
|
||||
|
||||
// Detach a thread to spin the console read indefinitely.
|
||||
// This application exits when the connection is closed, so
|
||||
// the connection's lifetime will outlast this thread.
|
||||
std::thread([connection, outputHandle, inputHandle] {
|
||||
ConsoleInputReader reader{ inputHandle };
|
||||
reader.SetWindowSizeChangedCallback([&]() {
|
||||
const auto size = GetConsoleScreenSize(outputHandle);
|
||||
|
||||
connection.Resize(size.height, size.width);
|
||||
});
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto input = reader.Read();
|
||||
if (input)
|
||||
{
|
||||
connection.WriteInput(winrt_wstring_to_array_view(*input));
|
||||
}
|
||||
}
|
||||
}).detach();
|
||||
|
||||
std::condition_variable stateChangeVar;
|
||||
std::optional<ConnectionState> state;
|
||||
std::mutex stateMutex;
|
||||
|
||||
connection.StateChanged([&](auto&& /*s*/, auto&& /*e*/) {
|
||||
std::unique_lock<std::mutex> lg{ stateMutex };
|
||||
state = connection.State();
|
||||
stateChangeVar.notify_all();
|
||||
});
|
||||
|
||||
connection.Start();
|
||||
|
||||
std::unique_lock<std::mutex> lg{ stateMutex };
|
||||
stateChangeVar.wait(lg, [&]() {
|
||||
if (!state.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return state.value() == ConnectionState::Closed || state.value() == ConnectionState::Failed;
|
||||
});
|
||||
|
||||
return state.value();
|
||||
}
|
||||
|
||||
int wmain(int /*argc*/, wchar_t** /*argv*/)
|
||||
{
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
DWORD inputMode{}, outputMode{};
|
||||
auto conIn{ GetStdHandle(STD_INPUT_HANDLE) }, conOut{ GetStdHandle(STD_OUTPUT_HANDLE) };
|
||||
auto codepage{ GetConsoleCP() }, outputCodepage{ GetConsoleOutputCP() };
|
||||
|
||||
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conIn, &inputMode));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(GetConsoleMode(conOut, &outputMode));
|
||||
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conIn, ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleMode(conOut, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_WRAP_AT_EOL_OUTPUT | DISABLE_NEWLINE_AUTO_RETURN));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleCP(CP_UTF8));
|
||||
RETURN_IF_WIN32_BOOL_FALSE(SetConsoleOutputCP(CP_UTF8));
|
||||
|
||||
auto restoreConsoleModes = wil::scope_exit([&]() {
|
||||
SetConsoleMode(conIn, inputMode);
|
||||
SetConsoleMode(conOut, outputMode);
|
||||
SetConsoleCP(codepage);
|
||||
SetConsoleOutputCP(outputCodepage);
|
||||
});
|
||||
|
||||
const auto size = GetConsoleScreenSize(conOut);
|
||||
|
||||
AzureConnection azureConn{};
|
||||
winrt::Windows::Foundation::Collections::ValueSet vs{};
|
||||
vs.Insert(L"initialRows", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.height)));
|
||||
vs.Insert(L"initialCols", winrt::Windows::Foundation::PropertyValue::CreateUInt32(gsl::narrow_cast<uint32_t>(size.width)));
|
||||
azureConn.Initialize(vs);
|
||||
|
||||
const auto state = RunConnectionToCompletion(azureConn, conOut, conIn);
|
||||
|
||||
return state == ConnectionState::Closed ? 0 : 1;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
@@ -1,40 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- pch.h
|
||||
|
||||
Abstract:
|
||||
- Contains external headers to include in the precompile phase of console build process.
|
||||
- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building).
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Ignore checked iterators warning from VC compiler.
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
// Block minwindef.h min/max macros to prevent <algorithm> conflict
|
||||
#define NOMINMAX
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
#include <Unknwn.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "../inc/LibraryIncludes.h"
|
||||
|
||||
#include <wil/cppwinrt.h>
|
||||
|
||||
#include <winrt/Windows.system.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <wil/win32_helpers.h>
|
||||
|
||||
#include <cppwinrt_utils.h>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,10 +330,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - bool: whether the current focus is on the search box
|
||||
bool SearchBoxControl::ContainsFocus()
|
||||
{
|
||||
auto focusedElement = Input::FocusManager::GetFocusedElement(this->XamlRoot());
|
||||
if (_focusableElements.count(focusedElement) > 0)
|
||||
// BODGY: It is possible for this to get called with no XAML root. We are unsure why.
|
||||
if (auto root = XamlRoot())
|
||||
{
|
||||
return true;
|
||||
auto focusedElement = Input::FocusManager::GetFocusedElement(root);
|
||||
if (_focusableElements.count(focusedElement) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -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)
|
||||
@@ -3163,12 +3159,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto weak = get_weak();
|
||||
|
||||
if (e.DataView().Contains(StandardDataFormats::ApplicationLink()))
|
||||
{
|
||||
try
|
||||
{
|
||||
auto link{ co_await e.DataView().GetApplicationLinkAsync() };
|
||||
_pasteTextWithBroadcast(link.AbsoluteUri());
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
_pasteTextWithBroadcast(link.AbsoluteUri());
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -3177,7 +3178,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
try
|
||||
{
|
||||
auto link{ co_await e.DataView().GetWebLinkAsync() };
|
||||
_pasteTextWithBroadcast(link.AbsoluteUri());
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
_pasteTextWithBroadcast(link.AbsoluteUri());
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -3186,7 +3190,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
try
|
||||
{
|
||||
auto text{ co_await e.DataView().GetTextAsync() };
|
||||
_pasteTextWithBroadcast(text);
|
||||
if (const auto strong = weak.get())
|
||||
{
|
||||
_pasteTextWithBroadcast(text);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -3248,6 +3255,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
const auto strong = weak.get();
|
||||
if (!strong)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
std::wstring allPathsString;
|
||||
for (auto& fullPath : fullPaths)
|
||||
{
|
||||
@@ -3590,9 +3603,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
safe_void_coroutine TermControl::_updateSelectionMarkers(IInspectable /*sender*/, Control::UpdateSelectionMarkersEventArgs args)
|
||||
{
|
||||
if (!args)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto weakThis{ get_weak() };
|
||||
co_await resume_foreground(Dispatcher());
|
||||
if (weakThis.get() && args)
|
||||
if (const auto strong = weakThis.get())
|
||||
{
|
||||
if (_core.HasSelection() && !args.ClearMarkers())
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -162,7 +162,13 @@ namespace winrt::Microsoft::Terminal::UI::implementation
|
||||
IInspectable target = Target();
|
||||
if (!target)
|
||||
{
|
||||
target = FocusManager::GetFocusedElement(XamlRoot());
|
||||
auto root = XamlRoot();
|
||||
if (!root)
|
||||
{
|
||||
return;
|
||||
}
|
||||
target = FocusManager::GetFocusedElement(root);
|
||||
|
||||
if (!target)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -958,6 +958,12 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_NCACTIVATE:
|
||||
{
|
||||
const bool activated = LOWORD(wParam) != 0;
|
||||
_titlebar.Focused(activated);
|
||||
break;
|
||||
}
|
||||
case WM_SETCURSOR:
|
||||
return _OnSetCursor(wParam, lParam);
|
||||
case WM_DISPLAYCHANGE:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -827,6 +860,9 @@ safe_void_coroutine WindowEmperor::_showMessageBox(winrt::hstring message, bool
|
||||
|
||||
// We must yield to a background thread, because MessageBoxW() is a blocking call, and we can't
|
||||
// block the main thread. That would prevent us from servicing WM_COPYDATA messages and similar.
|
||||
//
|
||||
// NOTE: All remaining code of this function doesn't touch `this`, so we don't need weak/strong_ref.
|
||||
// NOTE NOTE: Don't touch `this` when you make changes here.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
const auto messageTitle = error ? IDS_ERROR_DIALOG_TITLE : IDS_HELP_DIALOG_TITLE;
|
||||
@@ -858,6 +894,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 +905,25 @@ 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.
|
||||
//
|
||||
// Wrapping it in an exception handler will prevent us from losing track of the window count, at
|
||||
// the perceived cost of leaking all the resources. However, the resources were being leaked
|
||||
// anyway (since we threw and exited this message handler) so this at least gives back our
|
||||
// deterministic window count management.
|
||||
const auto strong = *it;
|
||||
_windows.erase(it);
|
||||
try
|
||||
{
|
||||
strong->Close();
|
||||
}
|
||||
CATCH_LOG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -937,7 +993,13 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
||||
if (isCurrentlyDark != _currentSystemThemeIsDark)
|
||||
{
|
||||
_currentSystemThemeIsDark = isCurrentlyDark;
|
||||
_app.Logic().ReloadSettings();
|
||||
|
||||
// GH#19505: WM_SETTINGCHANGE gets sent out with a SendMessage() call, which means
|
||||
// that COM methods marked as [input_sync] cannot be called. Well, our CascadiaSettings
|
||||
// loader does call such methods. This results in RPC_E_CANTCALLOUT_ININPUTSYNCCALL, aka:
|
||||
// "An outgoing call cannot be made since the application is dispatching an input-synchronous call."
|
||||
// The solution is to simply do it in another tick.
|
||||
_app.Logic().ReloadSettingsThrottled();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -65,15 +65,6 @@ namespace std
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<winrt::hstring, wchar_t> : fmt::formatter<fmt::wstring_view, wchar_t>
|
||||
{
|
||||
auto format(const winrt::hstring& str, auto& ctx) const
|
||||
{
|
||||
return fmt::formatter<fmt::wstring_view, wchar_t>::format({ str.data(), str.size() }, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
// This is a helper macro for both declaring the signature of an event, and
|
||||
// defining the body. Winrt events need a method for adding a callback to the
|
||||
// event and removing the callback. This macro will both declare the method
|
||||
|
||||
@@ -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>
|
||||
@@ -107,16 +114,6 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_AzureConnectionInProc</name>
|
||||
<description>Host the AzureConnection inside Terminal rather than via TerminalAzBridge</description>
|
||||
<id>4661</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_ShellCompletions</name>
|
||||
<description>An experimental escape sequence for client applications to request the Terminal display a list of suggestions.</description>
|
||||
@@ -133,10 +130,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
|
||||
|
||||
@@ -129,4 +129,47 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
// fmt::format but for HSTRING.
|
||||
template<typename... Args>
|
||||
winrt::hstring hstring_format(Args&&... args)
|
||||
{
|
||||
// We could use fmt::formatted_size and winrt::impl::hstring_builder here,
|
||||
// and this would make formatting of large strings a bit faster, and a bit slower
|
||||
// for short strings. More importantly, I hit compilation issues so I dropped that.
|
||||
fmt::basic_memory_buffer<wchar_t> buf;
|
||||
fmt::format_to(std::back_inserter(buf), args...);
|
||||
return winrt::hstring{ buf.data(), gsl::narrow<uint32_t>(buf.size()) };
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<winrt::hstring, wchar_t> : fmt::formatter<fmt::wstring_view, wchar_t>
|
||||
{
|
||||
auto format(const winrt::hstring& str, auto& ctx) const
|
||||
{
|
||||
return fmt::formatter<fmt::wstring_view, wchar_t>::format({ str.data(), str.size() }, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<winrt::guid, wchar_t> : fmt::formatter<fmt::wstring_view, wchar_t>
|
||||
{
|
||||
auto format(const winrt::guid& value, auto& ctx) const
|
||||
{
|
||||
return fmt::format_to(
|
||||
ctx.out(),
|
||||
L"{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
|
||||
value.Data1,
|
||||
value.Data2,
|
||||
value.Data3,
|
||||
value.Data4[0],
|
||||
value.Data4[1],
|
||||
value.Data4[2],
|
||||
value.Data4[3],
|
||||
value.Data4[4],
|
||||
value.Data4[5],
|
||||
value.Data4[6],
|
||||
value.Data4[7]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -45,10 +45,13 @@
|
||||
<ClInclude Include="..\..\inc\til\bytes.h" />
|
||||
<ClInclude Include="..\..\inc\til\coalesce.h" />
|
||||
<ClInclude Include="..\..\inc\til\color.h" />
|
||||
<ClInclude Include="..\..\inc\til\colorbrewer.h" />
|
||||
<ClInclude Include="..\..\inc\til\enumset.h" />
|
||||
<ClInclude Include="..\..\inc\til\env.h" />
|
||||
<ClInclude Include="..\..\inc\til\flat_set.h" />
|
||||
<ClInclude Include="..\..\inc\til\generational.h" />
|
||||
<ClInclude Include="..\..\inc\til\hash.h" />
|
||||
<ClInclude Include="..\..\inc\til\io.h" />
|
||||
<ClInclude Include="..\..\inc\til\latch.h" />
|
||||
<ClInclude Include="..\..\inc\til\math.h" />
|
||||
<ClInclude Include="..\..\inc\til\mutex.h" />
|
||||
@@ -57,6 +60,7 @@
|
||||
<ClInclude Include="..\..\inc\til\point.h" />
|
||||
<ClInclude Include="..\..\inc\til\rand.h" />
|
||||
<ClInclude Include="..\..\inc\til\rect.h" />
|
||||
<ClInclude Include="..\..\inc\til\regex.h" />
|
||||
<ClInclude Include="..\..\inc\til\replace.h" />
|
||||
<ClInclude Include="..\..\inc\til\rle.h" />
|
||||
<ClInclude Include="..\..\inc\til\size.h" />
|
||||
@@ -69,6 +73,7 @@
|
||||
<ClInclude Include="..\..\inc\til\type_traits.h" />
|
||||
<ClInclude Include="..\..\inc\til\u8u16convert.h" />
|
||||
<ClInclude Include="..\..\inc\til\unicode.h" />
|
||||
<ClInclude Include="..\..\inc\til\winrt.h" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natstepfilter" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\precomp.cpp" />
|
||||
@@ -121,6 +123,21 @@
|
||||
<ClInclude Include="..\..\inc\til\type_traits.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\colorbrewer.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\flat_set.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\io.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\regex.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\winrt.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="inc">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user