Merge remote-tracking branch 'origin/main' into dev/migrie/oop/ragnarok
This commit is contained in:
commit
51486a4168
1
.github/actions/spelling/excludes.txt
vendored
1
.github/actions/spelling/excludes.txt
vendored
|
@ -67,6 +67,7 @@ SUMS$
|
|||
^src/terminal/parser/ft_fuzzer/run\.bat$
|
||||
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
|
||||
^src/terminal/parser/ft_fuzzwrapper/run\.bat$
|
||||
^src/terminal/parser/ut_parser/Base64Test.cpp$
|
||||
^src/terminal/parser/ut_parser/run\.bat$
|
||||
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
|
||||
^src/tools/lnkd/lnkd\.bat$
|
||||
|
|
3
.github/actions/spelling/expect/expect.txt
vendored
3
.github/actions/spelling/expect/expect.txt
vendored
|
@ -938,6 +938,7 @@ GTP
|
|||
guc
|
||||
gui
|
||||
guidatom
|
||||
guiddef
|
||||
GValue
|
||||
GWL
|
||||
GWLP
|
||||
|
@ -1535,6 +1536,7 @@ NOCOLOR
|
|||
NOCOMM
|
||||
NOCONTEXTHELP
|
||||
NOCOPYBITS
|
||||
nodefaultlib
|
||||
nodiscard
|
||||
NODUP
|
||||
noexcept
|
||||
|
@ -2232,6 +2234,7 @@ STARTWPARMSW
|
|||
Statusline
|
||||
stdafx
|
||||
STDAPI
|
||||
stdc
|
||||
stdcall
|
||||
stdcpp
|
||||
stderr
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Overview
|
||||
|
||||
This document outlines the roadmap towards delivering Windows Terminal 2.0 by Winter 2021.
|
||||
This document outlines the roadmap towards delivering Windows Terminal 2.0.
|
||||
|
||||
## Milestones
|
||||
|
||||
|
@ -32,8 +32,8 @@ Below is the schedule for when milestones will be included in release builds of
|
|||
| 2021-07-14 | [1.10] in Windows Terminal Preview<br>[1.9] in Windows Terminal | [Windows Terminal Preview 1.10 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-10-release/) |
|
||||
| 2021-08-31 | [1.11] in Windows Terminal Preview<br>[1.10] in Windows Terminal | [Windows Terminal Preview 1.11 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-11-release/) |
|
||||
| 2021-10-20 | [1.12] in Windows Terminal Preview<br>[1.11] in Windows Terminal | [Windows Terminal Preview 1.12 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release/) |
|
||||
| 2021-11-30 | 2.0 RC in Windows Terminal Preview<br>2.0 RC in Windows Terminal | |
|
||||
| 2021-12-31 | [2.0] in Windows Terminal Preview<br>[2.0] in Windows Terminal | |
|
||||
| | 2.0 RC in Windows Terminal Preview<br>2.0 RC in Windows Terminal | |
|
||||
| | [2.0] in Windows Terminal Preview<br>[2.0] in Windows Terminal | |
|
||||
|
||||
## Issue Triage & Prioritization
|
||||
|
||||
|
@ -49,28 +49,32 @@ The following are a list of the key scenarios we're aiming to deliver for Termin
|
|||
|
||||
> 👉 Note: There are many other features that don't fit within 2.0, but will be re-assessed and prioritized for 3.0, the plan for which will be published in 2021.
|
||||
|
||||
| Priority\* | Scenario | Description/Notes |
|
||||
| ---------- | -------- | ----------------- |
|
||||
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564]<br>Specs: [#6720], [#6904]<br>Implementation: [#7283], [#7370], [#8048] |
|
||||
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193]<br>Implementation: [#6635] |
|
||||
| 1 | Tab tear-off | The ability to tear a tab out of the current window and spawn a new window or attach it to a separate window.<br><br>Issue: [#1256], [#5000]<br>Spec: [#2080], [#7240] |
|
||||
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574]<br>Implementation: [#7251] |
|
||||
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080], [#7414] |
|
||||
| 1 | Overall theme support | Tab coloring, title bar coloring, pane border coloring, pane border width, definition of what makes a theme<br><br>Issue: [#3327]<br>Spec: [#5772] |
|
||||
| 1 | Open profile elevated | Configure profiles to always open elevated (if Terminal was run unelevated)<br><br>Issue: [#5000], [#632]<br>Spec: [#8455] |
|
||||
| 1 | Open tab in existing window | Open new tabs in existing Terminal windows<br><br>Issue: [#5000], [#4472]<br>Spec: [#8135] |
|
||||
| 1 | Traditional opacity | Have a transparent background without the acrylic blur.<br><br>Issue: [#603] <br>**Current State**: Blocked on WinUI 3.0 |
|
||||
| 2 | SnapOnOutput, scroll lock | Pause output or scrolling on click.<br><br>Issue: [#980]<br>Spec: [#2529]<br>Implementation: [#6062] |
|
||||
| 2 | Infinite scrollback | Have an infinite history for the text buffer.<br><br>Issue: [#1410] |
|
||||
| 2 | Pane management | All issues listed out in the original issue. Some features include pane resizing with mouse, pane zooming, and opening a pane by prompting which profile to use.<br><br>Issue: [#1000] |
|
||||
| 2 | Theme marketplace | Marketplace for creation and distribution of themes.<br>Dependent on overall theming |
|
||||
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576]<br>Implementation: [#7515] |
|
||||
| 2 | Open with multiple tabs | A setting that allows Windows Terminal to launch with a specific tab configuration (not using only command line arguments).<br><br>Issue: [#756] |
|
||||
| 3 | Open in Windows Terminal | Functionality to right click on a file or folder and select Open in Windows Terminal.<br><br>Issue: [#1060]<br>Implementation: [#6100] |
|
||||
| 3 | Session restoration | Launch Windows Terminal and the previous session is restored with the proper tab and pane configuration and starting directories.<br><br>Issues: [#961], [#960], [#766] |
|
||||
| 3 | Quake mode | Provide a quick launch terminal that appears and disappears when a hotkey is pressed.<br><br>Issue: [#653] |
|
||||
| 3 | Settings migration infrastructure | Migrate people's settings without breaking them. Hand-in-hand with settings UI. |
|
||||
| 3 | Pointer bindings | Provide settings that can be bound to the mouse.<br><br>Issue: [#1553] |
|
||||
| Priority\* | Scenario | Description/Notes | State |
|
||||
| ---------- | -------- | ----------------- | ----- |
|
||||
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564]<br>Specs: [#6720], [#6904]<br>Implementation: [#7283], [#7370], [#8048] | ✔️ |
|
||||
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193]<br>Implementation: [#6635] | ✔️ |
|
||||
| 1 | Tab tear-off | The ability to tear a tab out of the current window and spawn a new window or attach it to a separate window.<br><br>Issue: [#1256], [#5000]<br>Spec: [#2080], [#7240] | 📝 |
|
||||
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574]<br>Implementation: [#7251] | ✔️ |
|
||||
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080], [#7414] | ✔️ |
|
||||
| 1 | Overall theme support | Tab coloring, title bar coloring, pane border coloring, pane border width, definition of what makes a theme<br><br>Issue: [#3327]<br>Spec: [#5772] | 🦶 |
|
||||
| 1 | Open profile elevated | Configure profiles to always open elevated (if Terminal was run unelevated)<br><br>Issue: [#5000], [#632]<br>Spec: [#8455] | 📝 |
|
||||
| 1 | Open tab in existing window | Open new tabs in existing Terminal windows<br><br>Issue: [#5000], [#4472]<br>Spec: [#8135] | ✔️ |
|
||||
| 1 | Traditional opacity | Have a transparent background without the acrylic blur.<br><br>Issue: [#603] | ✔️ |
|
||||
| 2 | SnapOnOutput, scroll lock | Pause output or scrolling on click.<br><br>Issue: [#980]<br>Spec: [#2529]<br>Implementation: [#6062] | ✔️ |
|
||||
| 2 | Infinite scrollback | Have an infinite history for the text buffer.<br><br>Issue: [#1410] | 🦶 |
|
||||
| 2 | Pane management | All issues listed out in the original issue. Some features include pane resizing with mouse, pane zooming, and opening a pane by prompting which profile to use.<br><br>Issue: [#1000] | 📝 |
|
||||
| 2 | Theme marketplace | Marketplace for creation and distribution of themes.<br>Dependent on overall theming | 🦶 |
|
||||
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576]<br>Implementation: [#7515] | ✔️ |
|
||||
| 2 | Open with multiple tabs | A setting that allows Windows Terminal to launch with a specific tab configuration (not using only command line arguments).<br><br>Issue: [#756] | ✔️ |
|
||||
| 3 | Open in Windows Terminal | Functionality to right click on a file or folder and select Open in Windows Terminal.<br><br>Issue: [#1060]<br>Implementation: [#6100] | ✔️ |
|
||||
| 3 | Session restoration | Launch Windows Terminal and the previous session is restored with the proper tab and pane configuration and starting directories.<br><br>Issues: [#961], [#960], [#766] | ✔️ |
|
||||
| 3 | Quake mode | Provide a quick launch terminal that appears and disappears when a hotkey is pressed.<br><br>Issue: [#653] | ✔️ |
|
||||
| 3 | Settings migration infrastructure | Migrate people's settings without breaking them. Hand-in-hand with settings UI. | 🦶 |
|
||||
| 3 | Pointer bindings | Provide settings that can be bound to the mouse.<br><br>Issue: [#1553] | 🦶 |
|
||||
|
||||
* 📝: The feature is currently in progress
|
||||
* ✔️: The feature is complete and shipped in a Preview build
|
||||
* 🦶: The feature is at risk of being punted to a future release cycle (beyond 2.0)
|
||||
|
||||
Feature Notes:
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include "../TerminalSettingsModel/CascadiaSettings.h"
|
||||
#include "JsonTestClass.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
#include <defaults.h>
|
||||
#include <userDefaults.h>
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace WEX::Logging;
|
||||
|
@ -70,6 +72,7 @@ namespace SettingsModelLocalTests
|
|||
TEST_METHOD(TestCloneInheritanceTree);
|
||||
TEST_METHOD(TestValidDefaults);
|
||||
TEST_METHOD(TestInheritedCommand);
|
||||
TEST_METHOD(LoadFragmentsWithMultipleUpdates);
|
||||
|
||||
private:
|
||||
static winrt::com_ptr<implementation::CascadiaSettings> createSettings(const std::string_view& userJSON)
|
||||
|
@ -1979,4 +1982,34 @@ namespace SettingsModelLocalTests
|
|||
VERIFY_IS_NULL(actualKeyChord);
|
||||
}
|
||||
}
|
||||
|
||||
// This test ensures GH#11597 doesn't regress.
|
||||
void DeserializationTests::LoadFragmentsWithMultipleUpdates()
|
||||
{
|
||||
static constexpr std::wstring_view fragmentSource{ L"fragment" };
|
||||
static constexpr std::string_view fragmentJson{ R"({
|
||||
"profiles": [
|
||||
{
|
||||
"updates": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
|
||||
"cursorShape": "filledBox"
|
||||
},
|
||||
{
|
||||
"updates": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
|
||||
"cursorShape": "filledBox"
|
||||
},
|
||||
{
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
implementation::SettingsLoader loader{ std::string_view{}, DefaultJson };
|
||||
loader.MergeInboxIntoUserSettings();
|
||||
loader.MergeFragmentIntoUserSettings(winrt::hstring{ fragmentSource }, fragmentJson);
|
||||
loader.FinalizeLayering();
|
||||
|
||||
VERIFY_IS_FALSE(loader.duplicateProfile);
|
||||
VERIFY_ARE_EQUAL(3u, loader.userSettings.profiles.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<Grid x:Name="Root"
|
||||
Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
@ -22,8 +23,50 @@
|
|||
<local:TabRowControl x:Name="TabRow"
|
||||
Grid.Row="0" />
|
||||
|
||||
<StackPanel Grid.Row="1">
|
||||
<mux:InfoBar x:Name="KeyboardServiceWarningInfoBar"
|
||||
x:Load="False"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Message="{x:Bind KeyboardServiceDisabledText, Mode=OneWay}"
|
||||
Severity="Warning">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<Button x:Uid="InfoBarDismissButton"
|
||||
Click="_KeyboardServiceWarningInfoDismissHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
|
||||
<mux:InfoBar x:Name="CloseOnExitInfoBar"
|
||||
x:Uid="CloseOnExitInfoBar"
|
||||
x:Load="False"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Severity="Informational">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<Button x:Uid="InfoBarDismissButton"
|
||||
Click="_CloseOnExitInfoDismissHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
|
||||
<mux:InfoBar x:Name="SetAsDefaultInfoBar"
|
||||
x:Uid="SetAsDefaultInfoBar"
|
||||
x:Load="False"
|
||||
CloseButtonClick="_SetAsDefaultDismissHandler"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Severity="Informational">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<HyperlinkButton x:Uid="SetAsDefaultTip_OpenSettingsLink"
|
||||
Click="_SetAsDefaultOpenSettingsHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
</StackPanel>
|
||||
|
||||
<Grid x:Name="TabContent"
|
||||
Grid.Row="1"
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch" />
|
||||
|
||||
|
@ -115,48 +158,6 @@
|
|||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<StackPanel>
|
||||
<mux:InfoBar x:Name="KeyboardServiceWarningInfoBar"
|
||||
x:Load="False"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Message="{x:Bind KeyboardServiceDisabledText, Mode=OneWay}"
|
||||
Severity="Warning">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<Button x:Uid="InfoBarDismissButton"
|
||||
Click="_KeyboardServiceWarningInfoDismissHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
|
||||
<mux:InfoBar x:Name="CloseOnExitInfoBar"
|
||||
x:Uid="CloseOnExitInfoBar"
|
||||
x:Load="False"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Severity="Informational">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<Button x:Uid="InfoBarDismissButton"
|
||||
Click="_CloseOnExitInfoDismissHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
|
||||
<mux:InfoBar x:Name="SetAsDefaultInfoBar"
|
||||
x:Uid="SetAsDefaultInfoBar"
|
||||
x:Load="False"
|
||||
CloseButtonClick="_SetAsDefaultDismissHandler"
|
||||
IsClosable="True"
|
||||
IsIconVisible="True"
|
||||
IsOpen="False"
|
||||
Severity="Informational">
|
||||
<mux:InfoBar.ActionButton>
|
||||
<HyperlinkButton x:Uid="SetAsDefaultTip_OpenSettingsLink"
|
||||
Click="_SetAsDefaultOpenSettingsHandler" />
|
||||
</mux:InfoBar.ActionButton>
|
||||
</mux:InfoBar>
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
A TeachingTip with IsLightDismissEnabled="True" will immediately
|
||||
dismiss itself if the window is unfocused (In Xaml Islands). This is
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../terminal/adapter/DispatchTypes.hpp"
|
||||
#include "../../terminal/input/terminalInput.hpp"
|
||||
#include "../../buffer/out/TextAttribute.hpp"
|
||||
#include "../../types/inc/Viewport.hpp"
|
||||
|
||||
|
@ -47,16 +48,9 @@ namespace Microsoft::Terminal::Core
|
|||
virtual bool SetDefaultForeground(const DWORD color) noexcept = 0;
|
||||
virtual bool SetDefaultBackground(const DWORD color) noexcept = 0;
|
||||
|
||||
virtual bool EnableWin32InputMode(const bool win32InputMode) noexcept = 0;
|
||||
virtual bool SetCursorKeysMode(const bool applicationMode) noexcept = 0;
|
||||
virtual bool SetKeypadMode(const bool applicationMode) noexcept = 0;
|
||||
virtual bool SetInputMode(const ::Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) noexcept = 0;
|
||||
|
||||
virtual bool SetScreenMode(const bool reverseMode) noexcept = 0;
|
||||
virtual bool EnableVT200MouseMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableSGRExtendedMouseMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableButtonEventMouseMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableAnyEventMouseMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableAlternateScrollMode(const bool enabled) noexcept = 0;
|
||||
virtual bool EnableXtermBracketedPasteMode(const bool enabled) noexcept = 0;
|
||||
virtual bool IsXtermBracketedPasteModeEnabled() const = 0;
|
||||
|
||||
|
|
|
@ -113,16 +113,9 @@ public:
|
|||
bool SetDefaultForeground(const COLORREF color) noexcept override;
|
||||
bool SetDefaultBackground(const COLORREF color) noexcept override;
|
||||
|
||||
bool EnableWin32InputMode(const bool win32InputMode) noexcept override;
|
||||
bool SetCursorKeysMode(const bool applicationMode) noexcept override;
|
||||
bool SetKeypadMode(const bool applicationMode) noexcept override;
|
||||
bool SetInputMode(const ::Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) noexcept override;
|
||||
|
||||
bool SetScreenMode(const bool reverseMode) noexcept override;
|
||||
bool EnableVT200MouseMode(const bool enabled) noexcept override;
|
||||
bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept override;
|
||||
bool EnableSGRExtendedMouseMode(const bool enabled) noexcept override;
|
||||
bool EnableButtonEventMouseMode(const bool enabled) noexcept override;
|
||||
bool EnableAnyEventMouseMode(const bool enabled) noexcept override;
|
||||
bool EnableAlternateScrollMode(const bool enabled) noexcept override;
|
||||
bool EnableXtermBracketedPasteMode(const bool enabled) noexcept override;
|
||||
bool IsXtermBracketedPasteModeEnabled() const noexcept override;
|
||||
|
||||
|
|
|
@ -482,23 +482,13 @@ til::color Terminal::GetDefaultBackground() const noexcept
|
|||
return _defaultBg;
|
||||
}
|
||||
|
||||
bool Terminal::EnableWin32InputMode(const bool win32InputMode) noexcept
|
||||
bool Terminal::SetInputMode(const TerminalInput::Mode mode, const bool enabled) noexcept
|
||||
try
|
||||
{
|
||||
_terminalInput->ChangeWin32InputMode(win32InputMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::SetCursorKeysMode(const bool applicationMode) noexcept
|
||||
{
|
||||
_terminalInput->ChangeCursorKeysMode(applicationMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::SetKeypadMode(const bool applicationMode) noexcept
|
||||
{
|
||||
_terminalInput->ChangeKeypadMode(applicationMode);
|
||||
_terminalInput->SetInputMode(mode, enabled);
|
||||
return true;
|
||||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::SetScreenMode(const bool reverseMode) noexcept
|
||||
try
|
||||
|
@ -511,42 +501,6 @@ try
|
|||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->EnableDefaultTracking(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->SetUtf8ExtendedMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableSGRExtendedMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->SetSGRExtendedMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableButtonEventMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->EnableButtonEventTracking(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableAnyEventMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->EnableAnyEventTracking(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableAlternateScrollMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalInput->EnableAlternateScroll(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Terminal::EnableXtermBracketedPasteMode(const bool enabled) noexcept
|
||||
{
|
||||
_bracketedPasteMode = enabled;
|
||||
|
|
|
@ -321,9 +321,9 @@ CATCH_LOG_RETURN_FALSE()
|
|||
// - applicationMode - set to true to enable Application Mode Input, false for Numeric Mode Input.
|
||||
// Return Value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::SetKeypadMode(const bool fApplicationMode) noexcept
|
||||
bool TerminalDispatch::SetKeypadMode(const bool applicationMode) noexcept
|
||||
{
|
||||
_terminalApi.SetKeypadMode(fApplicationMode);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::Keypad, applicationMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ bool TerminalDispatch::SetKeypadMode(const bool fApplicationMode) noexcept
|
|||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::SetCursorKeysMode(const bool applicationMode) noexcept
|
||||
{
|
||||
_terminalApi.SetCursorKeysMode(applicationMode);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::CursorKey, applicationMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ bool TerminalDispatch::SetScreenMode(const bool reverseMode) noexcept
|
|||
// - True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableWin32InputMode(const bool win32Mode) noexcept
|
||||
{
|
||||
_terminalApi.EnableWin32InputMode(win32Mode);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::Win32, win32Mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ bool TerminalDispatch::EnableWin32InputMode(const bool win32Mode) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableVT200MouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableVT200MouseMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::DefaultMouseTracking, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -384,7 +384,7 @@ bool TerminalDispatch::EnableVT200MouseMode(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableUTF8ExtendedMouseMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ bool TerminalDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableSGRExtendedMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableSGRExtendedMouseMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::SgrMouseEncoding, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,7 @@ bool TerminalDispatch::EnableSGRExtendedMouseMode(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableButtonEventMouseMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableAnyEventMouseMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool TerminalDispatch::EnableAlternateScroll(const bool enabled) noexcept
|
||||
{
|
||||
_terminalApi.EnableAlternateScrollMode(enabled);
|
||||
_terminalApi.SetInputMode(TerminalInput::Mode::AlternateScroll, enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void ApplyRuntimeInitialSettings();
|
||||
void MergeInboxIntoUserSettings();
|
||||
void FindFragmentsAndMergeIntoUserSettings();
|
||||
void MergeFragmentIntoUserSettings(const winrt::hstring& source, const std::string_view& content);
|
||||
void FinalizeLayering();
|
||||
bool DisableDeletedProfiles();
|
||||
|
||||
|
@ -82,7 +83,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void _parseFragment(const winrt::hstring& source, const std::string_view& content, ParsedSettings& settings);
|
||||
static JsonSettings _parseJson(const std::string_view& content);
|
||||
static winrt::com_ptr<implementation::Profile> _parseProfile(const OriginTag origin, const winrt::hstring& source, const Json::Value& profileJson);
|
||||
void _appendProfile(winrt::com_ptr<implementation::Profile>&& profile, ParsedSettings& settings);
|
||||
void _appendProfile(winrt::com_ptr<Profile>&& profile, const winrt::guid& guid, ParsedSettings& settings);
|
||||
static void _addParentProfile(const winrt::com_ptr<implementation::Profile>& profile, ParsedSettings& settings);
|
||||
void _executeGenerator(const IDynamicProfileGenerator& generator);
|
||||
|
||||
|
|
|
@ -207,26 +207,6 @@ void SettingsLoader::FindFragmentsAndMergeIntoUserSettings()
|
|||
{
|
||||
const auto content = ReadUTF8File(fragmentExt.path());
|
||||
_parseFragment(source, content, fragmentSettings);
|
||||
|
||||
for (const auto& fragmentProfile : fragmentSettings.profiles)
|
||||
{
|
||||
if (const auto updates = fragmentProfile->Updates(); updates != winrt::guid{})
|
||||
{
|
||||
if (const auto it = userSettings.profilesByGuid.find(updates); it != userSettings.profilesByGuid.end())
|
||||
{
|
||||
it->second->InsertParent(0, fragmentProfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_addParentProfile(fragmentProfile, userSettings);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& kv : fragmentSettings.globals->ColorSchemes())
|
||||
{
|
||||
userSettings.globals->AddColorScheme(kv.Value());
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
@ -289,6 +269,15 @@ void SettingsLoader::FindFragmentsAndMergeIntoUserSettings()
|
|||
}
|
||||
}
|
||||
|
||||
// See FindFragmentsAndMergeIntoUserSettings.
|
||||
// This function does the same, but for a single given JSON blob and source
|
||||
// and at the time of writing is used for unit tests only.
|
||||
void SettingsLoader::MergeFragmentIntoUserSettings(const winrt::hstring& source, const std::string_view& content)
|
||||
{
|
||||
ParsedSettings fragmentSettings;
|
||||
_parseFragment(source, content, fragmentSettings);
|
||||
}
|
||||
|
||||
// Call this method before passing SettingsLoader to the CascadiaSettings constructor.
|
||||
// It layers all remaining objects onto each other (those that aren't covered
|
||||
// by MergeInboxIntoUserSettings/FindFragmentsAndMergeIntoUserSettings).
|
||||
|
@ -475,7 +464,7 @@ void SettingsLoader::_parse(const OriginTag origin, const winrt::hstring& source
|
|||
// GH#9962: Discard Guid-less, Name-less profiles.
|
||||
if (profile->HasGuid())
|
||||
{
|
||||
_appendProfile(std::move(profile), settings);
|
||||
_appendProfile(std::move(profile), profile->Guid(), settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -517,14 +506,37 @@ void SettingsLoader::_parseFragment(const winrt::hstring& source, const std::str
|
|||
auto profile = _parseProfile(OriginTag::Fragment, source, profileJson);
|
||||
// GH#9962: Discard Guid-less, Name-less profiles, but...
|
||||
// allow ones with an Updates field, as those are special for fragments.
|
||||
if (profile->HasGuid() || profile->Updates() != winrt::guid{})
|
||||
// We need to make sure to only call Guid() if HasGuid() is true,
|
||||
// as Guid() will dynamically generate a return value otherwise.
|
||||
const auto guid = profile->HasGuid() ? profile->Guid() : profile->Updates();
|
||||
if (guid != winrt::guid{})
|
||||
{
|
||||
_appendProfile(std::move(profile), settings);
|
||||
_appendProfile(std::move(profile), guid, settings);
|
||||
}
|
||||
}
|
||||
CATCH_LOG()
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& fragmentProfile : settings.profiles)
|
||||
{
|
||||
if (const auto updates = fragmentProfile->Updates(); updates != winrt::guid{})
|
||||
{
|
||||
if (const auto it = userSettings.profilesByGuid.find(updates); it != userSettings.profilesByGuid.end())
|
||||
{
|
||||
it->second->InsertParent(0, fragmentProfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_addParentProfile(fragmentProfile, userSettings);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& kv : settings.globals->ColorSchemes())
|
||||
{
|
||||
userSettings.globals->AddColorScheme(kv.Value());
|
||||
}
|
||||
}
|
||||
|
||||
SettingsLoader::JsonSettings SettingsLoader::_parseJson(const std::string_view& content)
|
||||
|
@ -564,11 +576,11 @@ winrt::com_ptr<Profile> SettingsLoader::_parseProfile(const OriginTag origin, co
|
|||
|
||||
// Adds a profile to the ParsedSettings instance. Takes ownership of the profile.
|
||||
// It ensures no duplicate GUIDs are added to the ParsedSettings instance.
|
||||
void SettingsLoader::_appendProfile(winrt::com_ptr<Profile>&& profile, ParsedSettings& settings)
|
||||
void SettingsLoader::_appendProfile(winrt::com_ptr<Profile>&& profile, const winrt::guid& guid, ParsedSettings& settings)
|
||||
{
|
||||
// FYI: The static_cast ensures we don't move the profile into
|
||||
// `profilesByGuid`, even though we still need it later for `profiles`.
|
||||
if (settings.profilesByGuid.emplace(profile->Guid(), static_cast<const winrt::com_ptr<Profile>&>(profile)).second)
|
||||
if (settings.profilesByGuid.emplace(guid, static_cast<const winrt::com_ptr<Profile>&>(profile)).second)
|
||||
{
|
||||
settings.profiles.emplace_back(profile);
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
C4467: usage of ATL attributes is deprecated
|
||||
Conhost code still uses ATL.
|
||||
-->
|
||||
<DisableSpecificWarnings>4103;4201;4312;4467;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings>4103;4201;4312;4467;5105;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<PreprocessorDefinitions>_WINDOWS;EXTERNAL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
|
||||
|
@ -117,6 +117,7 @@
|
|||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
|
||||
<ControlFlowGuard>Guard</ControlFlowGuard>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<UseStandardPreprocessor>true</UseStandardPreprocessor>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj /Zc:twoPhase-</AdditionalOptions>
|
||||
<DisableSpecificWarnings>5104;5105;28204;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings>5104;28204;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
|
||||
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
|
||||
</ClCompile>
|
||||
|
|
|
@ -1248,55 +1248,6 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
|
|||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for changing the cursor keys input mode between normal and application mode.
|
||||
// The cursor keys are the arrows, plus Home and End.
|
||||
// Parameters:
|
||||
// - fApplicationMode - set to true to enable Application Mode Input, false for Numeric Mode Input.
|
||||
// Return value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetCursorKeysMode(_In_ bool fApplicationMode)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (gci.pInputBuffer == nullptr)
|
||||
{
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
gci.pInputBuffer->GetTerminalInput().ChangeCursorKeysMode(fApplicationMode);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for changing the keypad input mode between numeric and application mode.
|
||||
// This controls what the keys on the numpad translate to.
|
||||
// Parameters:
|
||||
// - fApplicationMode - set to true to enable Application Mode Input, false for Numeric Mode Input.
|
||||
// Return value:
|
||||
// - True if handled successfully. False otherwise.
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetKeypadMode(_In_ bool fApplicationMode)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (gci.pInputBuffer == nullptr)
|
||||
{
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
gci.pInputBuffer->GetTerminalInput().ChangeKeypadMode(fApplicationMode);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - A private API call which enables/disables sending full input records
|
||||
// encoded as a string of characters to the client application.
|
||||
// Parameters:
|
||||
// - win32InputMode - set to true to enable win32-input-mode, false to disable.
|
||||
// Return value:
|
||||
// - <none>
|
||||
void DoSrvPrivateEnableWin32InputMode(const bool win32InputMode)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.pInputBuffer->GetTerminalInput().ChangeWin32InputMode(win32InputMode);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for changing the screen mode between normal and reverse.
|
||||
// When in reverse screen mode, the background and foreground colors are switched.
|
||||
|
@ -1525,78 +1476,6 @@ void DoSrvPrivateUseMainScreenBuffer(SCREEN_INFORMATION& screenInfo)
|
|||
screenInfo.GetActiveBuffer().UseMainScreenBuffer();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling VT200 style mouse mode.
|
||||
// Parameters:
|
||||
// - fEnable - true to enable default tracking mode, false to disable mouse mode.
|
||||
// Return value:
|
||||
// - None
|
||||
void DoSrvPrivateEnableVT200MouseMode(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().EnableDefaultTracking(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling utf8 style mouse mode.
|
||||
// Parameters:
|
||||
// - fEnable - true to enable, false to disable.
|
||||
// Return value:
|
||||
// - None
|
||||
void DoSrvPrivateEnableUTF8ExtendedMouseMode(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().SetUtf8ExtendedMode(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling SGR style mouse mode.
|
||||
// Parameters:
|
||||
// - fEnable - true to enable, false to disable.
|
||||
// Return value:
|
||||
// - None
|
||||
void DoSrvPrivateEnableSGRExtendedMouseMode(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().SetSGRExtendedMode(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling button-event mouse mode.
|
||||
// Parameters:
|
||||
// - fEnable - true to enable button-event mode, false to disable mouse mode.
|
||||
// Return value:
|
||||
// - None
|
||||
void DoSrvPrivateEnableButtonEventMouseMode(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().EnableButtonEventTracking(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling any-event mouse mode.
|
||||
// Parameters:
|
||||
// - fEnable - true to enable any-event mode, false to disable mouse mode.
|
||||
// Return value:
|
||||
// - None
|
||||
void DoSrvPrivateEnableAnyEventMouseMode(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().EnableAnyEventTracking(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for enabling alternate scroll mode
|
||||
// Parameters:
|
||||
// - fEnable - true to enable alternate scroll mode, false to disable.
|
||||
// Return value:
|
||||
// None
|
||||
void DoSrvPrivateEnableAlternateScroll(const bool fEnable)
|
||||
{
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.GetActiveInputBuffer()->GetTerminalInput().EnableAlternateScroll(fEnable);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for performing a VT-style erase all operation on the buffer.
|
||||
// See SCREEN_INFORMATION::VtEraseAll's description for details.
|
||||
|
|
|
@ -18,10 +18,6 @@ Revision History:
|
|||
#include "../inc/conattrs.hpp"
|
||||
class SCREEN_INFORMATION;
|
||||
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetCursorKeysMode(_In_ bool fApplicationMode);
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetKeypadMode(_In_ bool fApplicationMode);
|
||||
void DoSrvPrivateEnableWin32InputMode(const bool win32InputMode);
|
||||
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetScreenMode(const bool reverseMode);
|
||||
[[nodiscard]] NTSTATUS DoSrvPrivateSetAutoWrapMode(const bool wrapAtEOL);
|
||||
|
||||
|
@ -35,13 +31,6 @@ void DoSrvPrivateAllowCursorBlinking(SCREEN_INFORMATION& screenInfo, const bool
|
|||
[[nodiscard]] NTSTATUS DoSrvPrivateUseAlternateScreenBuffer(SCREEN_INFORMATION& screenInfo);
|
||||
void DoSrvPrivateUseMainScreenBuffer(SCREEN_INFORMATION& screenInfo);
|
||||
|
||||
void DoSrvPrivateEnableVT200MouseMode(const bool fEnable);
|
||||
void DoSrvPrivateEnableUTF8ExtendedMouseMode(const bool fEnable);
|
||||
void DoSrvPrivateEnableSGRExtendedMouseMode(const bool fEnable);
|
||||
void DoSrvPrivateEnableButtonEventMouseMode(const bool fEnable);
|
||||
void DoSrvPrivateEnableAnyEventMouseMode(const bool fEnable);
|
||||
void DoSrvPrivateEnableAlternateScroll(const bool fEnable);
|
||||
|
||||
[[nodiscard]] HRESULT DoSrvPrivateEraseAll(SCREEN_INFORMATION& screenInfo);
|
||||
[[nodiscard]] HRESULT DoSrvPrivateClearBuffer(SCREEN_INFORMATION& screenInfo);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
using namespace Microsoft::Console;
|
||||
using Microsoft::Console::Interactivity::ServiceLocator;
|
||||
using Microsoft::Console::VirtualTerminal::TerminalInput;
|
||||
|
||||
WriteBuffer::WriteBuffer(_In_ Microsoft::Console::IIoProvider& io) :
|
||||
_io{ io },
|
||||
|
@ -237,43 +238,28 @@ bool ConhostInternalGetSet::SetConsoleWindowInfo(const bool absolute, const SMAL
|
|||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateSetCursorKeysMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateSetCursorKeysMode is an internal-only "API" call that the vt commands can execute,
|
||||
// - Sets the various terminal input modes.
|
||||
// SetInputMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - fApplicationMode - set to true to enable Application Mode Input, false for Normal Mode.
|
||||
// - mode - the input mode to change.
|
||||
// - enabled - set to true to enable the mode, false to disable it.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateSetCursorKeysMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateSetCursorKeysMode(const bool fApplicationMode)
|
||||
// - true if successful. false otherwise.
|
||||
bool ConhostInternalGetSet::SetInputMode(const TerminalInput::Mode mode, const bool enabled)
|
||||
{
|
||||
return NT_SUCCESS(DoSrvPrivateSetCursorKeysMode(fApplicationMode));
|
||||
}
|
||||
auto& terminalInput = _io.GetActiveInputBuffer()->GetTerminalInput();
|
||||
terminalInput.SetInputMode(mode, enabled);
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateSetKeypadMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateSetKeypadMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - fApplicationMode - set to true to enable Application Mode Input, false for Numeric Mode.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateSetKeypadMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateSetKeypadMode(const bool fApplicationMode)
|
||||
{
|
||||
return NT_SUCCESS(DoSrvPrivateSetKeypadMode(fApplicationMode));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableWin32InputMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableWin32InputMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - win32InputMode - set to true to enable win32-input-mode, false to disable.
|
||||
// Return Value:
|
||||
// - true always
|
||||
bool ConhostInternalGetSet::PrivateEnableWin32InputMode(const bool win32InputMode)
|
||||
{
|
||||
DoSrvPrivateEnableWin32InputMode(win32InputMode);
|
||||
return true;
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always pass input mode requests
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input.
|
||||
// The original comment said, "Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911". Unfortunately, time has shown
|
||||
// us that SSH 7.7 _also_ requests mouse input and that can have a user interface
|
||||
// impact on the actual connected terminal. We can't remove this check,
|
||||
// because SSH <=7.7 is out in the wild on all versions of Windows <=2004.
|
||||
return !(IsConsolePty() && PrivateIsVtInputEnabled());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -289,7 +275,7 @@ bool ConhostInternalGetSet::PrivateSetAnsiMode(const bool ansiMode)
|
|||
auto& stateMachine = _io.GetActiveOutputBuffer().GetStateMachine();
|
||||
stateMachine.SetAnsiMode(ansiMode);
|
||||
auto& terminalInput = _io.GetActiveInputBuffer()->GetTerminalInput();
|
||||
terminalInput.ChangeAnsiMode(ansiMode);
|
||||
terminalInput.SetInputMode(TerminalInput::Mode::Ansi, ansiMode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -448,90 +434,6 @@ bool ConhostInternalGetSet::PrivateUseMainScreenBuffer()
|
|||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableVT200MouseMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableVT200MouseMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable vt200 mouse mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableVT200MouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableVT200MouseMode(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableVT200MouseMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableUTF8ExtendedMouseMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableUTF8ExtendedMouseMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable utf8 extended mouse mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableUTF8ExtendedMouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableUTF8ExtendedMouseMode(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableUTF8ExtendedMouseMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableSGRExtendedMouseMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableSGRExtendedMouseMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable SGR extended mouse mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableSGRExtendedMouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableSGRExtendedMouseMode(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableSGRExtendedMouseMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableButtonEventMouseMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableButtonEventMouseMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable button-event mouse mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableButtonEventMouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableButtonEventMouseMode(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableButtonEventMouseMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableAnyEventMouseMode call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableAnyEventMouseMode is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable any-event mouse mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableAnyEventMouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableAnyEventMouseMode(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableAnyEventMouseMode(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEnableAlternateScroll call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEnableAlternateScroll is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on out public API surface.
|
||||
// Arguments:
|
||||
// - enabled - set to true to enable alternate scroll mode, false to disable
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateEnableAnyEventMouseMode). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateEnableAlternateScroll(const bool enabled)
|
||||
{
|
||||
DoSrvPrivateEnableAlternateScroll(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateEraseAll call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// PrivateEraseAll is an internal-only "API" call that the vt commands can execute,
|
||||
|
|
|
@ -72,9 +72,7 @@ public:
|
|||
bool SetConsoleWindowInfo(bool const absolute,
|
||||
const SMALL_RECT& window) override;
|
||||
|
||||
bool PrivateSetCursorKeysMode(const bool applicationMode) override;
|
||||
bool PrivateSetKeypadMode(const bool applicationMode) override;
|
||||
bool PrivateEnableWin32InputMode(const bool win32InputMode) override;
|
||||
bool SetInputMode(const Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) override;
|
||||
|
||||
bool PrivateSetAnsiMode(const bool ansiMode) override;
|
||||
bool PrivateSetScreenMode(const bool reverseMode) override;
|
||||
|
@ -97,12 +95,6 @@ public:
|
|||
|
||||
bool PrivateUseMainScreenBuffer() override;
|
||||
|
||||
bool PrivateEnableVT200MouseMode(const bool enabled) override;
|
||||
bool PrivateEnableUTF8ExtendedMouseMode(const bool enabled) override;
|
||||
bool PrivateEnableSGRExtendedMouseMode(const bool enabled) override;
|
||||
bool PrivateEnableButtonEventMouseMode(const bool enabled) override;
|
||||
bool PrivateEnableAnyEventMouseMode(const bool enabled) override;
|
||||
bool PrivateEnableAlternateScroll(const bool enabled) override;
|
||||
bool PrivateEraseAll() override;
|
||||
bool PrivateClearBuffer() override;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
<Midl Include="IConsoleHandoff.idl">
|
||||
<!--
|
||||
<!--
|
||||
In Razzle, IDL files generate %FileName%.h
|
||||
In Visual Studio, IDL files generate %FileName%_h.h
|
||||
Visual Studio is easier to override than Razzle.
|
||||
|
@ -31,6 +31,7 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="$(IntDir)\IConsoleHandoff.h" />
|
||||
<ClInclude Include="$(IntDir)\ITerminalHandoff.h" />
|
||||
<ClInclude Include="nodefaultlib_shim.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(IntDir)\dlldata.c" />
|
||||
|
@ -56,16 +57,27 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<CallingConvention>StdCall</CallingConvention>
|
||||
<AdditionalIncludeDirectories>.;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<CallingConvention Condition="'$(Platform)'!='ARM64'">StdCall</CallingConvention>
|
||||
<!-- Must be Stdcall on all platforms to resolve _ObjectStublessClient3 -->
|
||||
<PreprocessorDefinitions>REGISTER_PROXY_DLL;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<ForcedIncludeFiles>nodefaultlib_shim.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<ModuleDefinitionFile>OpenConsoleProxy.def</ModuleDefinitionFile>
|
||||
<!--
|
||||
Not depending on the CRT cuts binary size by half and prevents issues if this DLL
|
||||
is copied elsewhere and executed outside of our app package without our bundled CRT present.
|
||||
-->
|
||||
<AdditionalDependencies />
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<EntryPointSymbol>DllMain</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
<ClInclude Include="$(IntDir)\ITerminalHandoff.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nodefaultlib_shim.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="IConsoleHandoff.idl">
|
||||
|
|
8
src/host/proxy/nodefaultlib_shim.h
Normal file
8
src/host/proxy/nodefaultlib_shim.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
|
||||
#define memcmp(a, b, c) (!InlineIsEqualGUID(a, b))
|
|
@ -255,6 +255,14 @@ void Selection::ExtendSelection(_In_ COORD coordBufferPos)
|
|||
srNewSelection.Top = _coordSelectionAnchor.Y;
|
||||
}
|
||||
|
||||
// This function is called on WM_MOUSEMOVE.
|
||||
// Prevent triggering an invalidation just because the mouse moved
|
||||
// in the same cell without changing the actual (visible) selection.
|
||||
if (_srSelectionRect == srNewSelection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// call special update method to modify the displayed selection in-place
|
||||
// NOTE: Using HideSelection, editing the rectangle, then ShowSelection will cause flicker.
|
||||
//_PaintUpdateSelection(&srNewSelection);
|
||||
|
|
|
@ -1167,15 +1167,7 @@ bool AdaptDispatch::ResetMode(const DispatchTypes::ModeParams param)
|
|||
// - True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::SetKeypadMode(const bool fApplicationMode)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateSetKeypadMode(fApplicationMode);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::Keypad, fApplicationMode);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1187,15 +1179,7 @@ bool AdaptDispatch::SetKeypadMode(const bool fApplicationMode)
|
|||
// - True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableWin32InputMode(const bool win32InputMode)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableWin32InputMode(win32InputMode);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::Win32, win32InputMode);
|
||||
}
|
||||
|
||||
// - DECCKM - Sets the cursor keys input mode to either Application mode or Normal mode (true, false respectively)
|
||||
|
@ -1205,15 +1189,7 @@ bool AdaptDispatch::EnableWin32InputMode(const bool win32InputMode)
|
|||
// - True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::SetCursorKeysMode(const bool applicationMode)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateSetCursorKeysMode(applicationMode);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::CursorKey, applicationMode);
|
||||
}
|
||||
|
||||
// - att610 - Enables or disables the cursor blinking.
|
||||
|
@ -2096,15 +2072,7 @@ bool AdaptDispatch::EnableDECCOLMSupport(const bool enabled) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableVT200MouseMode(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableVT200MouseMode(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2116,15 +2084,7 @@ bool AdaptDispatch::EnableVT200MouseMode(const bool enabled)
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableUTF8ExtendedMouseMode(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableUTF8ExtendedMouseMode(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2136,15 +2096,7 @@ bool AdaptDispatch::EnableUTF8ExtendedMouseMode(const bool enabled)
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableSGRExtendedMouseMode(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableSGRExtendedMouseMode(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::SgrMouseEncoding, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2155,15 +2107,7 @@ bool AdaptDispatch::EnableSGRExtendedMouseMode(const bool enabled)
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableButtonEventMouseMode(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableButtonEventMouseMode(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2175,15 +2119,7 @@ bool AdaptDispatch::EnableButtonEventMouseMode(const bool enabled)
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableAnyEventMouseMode(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2195,15 +2131,7 @@ bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled)
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::EnableAlternateScroll(const bool enabled)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateEnableAlternateScroll(enabled);
|
||||
|
||||
if (_ShouldPassThroughInputModeChange())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
return _pConApi->SetInputMode(TerminalInput::Mode::AlternateScroll, enabled);
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
|
@ -2672,22 +2600,3 @@ void AdaptDispatch::_ReportDECSTBMSetting() const
|
|||
response += L"r\033\\";
|
||||
_WriteResponse(response);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Determines whether we should pass any sequence that manipulates
|
||||
// TerminalInput's input generator through the PTY. It encapsulates
|
||||
// a check for whether the PTY is in use.
|
||||
// Return value:
|
||||
// True if the request should be passed.
|
||||
bool AdaptDispatch::_ShouldPassThroughInputModeChange() const
|
||||
{
|
||||
// If we're a conpty, AND WE'RE IN VT INPUT MODE, always pass input mode requests
|
||||
// The VT Input mode check is to work around ssh.exe v7.7, which uses VT
|
||||
// output, but not Input.
|
||||
// The original comment said, "Once the conpty supports these types of input,
|
||||
// this check can be removed. See GH#4911". Unfortunately, time has shown
|
||||
// us that SSH 7.7 _also_ requests mouse input and that can have a user interface
|
||||
// impact on the actual connected terminal. We can't remove this check,
|
||||
// because SSH <=7.7 is out in the wild on all versions of Windows <=2004.
|
||||
return _pConApi->IsConsolePty() && _pConApi->PrivateIsVtInputEnabled();
|
||||
}
|
||||
|
|
|
@ -194,8 +194,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
void _ReportSGRSetting() const;
|
||||
void _ReportDECSTBMSetting() const;
|
||||
|
||||
bool _ShouldPassThroughInputModeChange() const;
|
||||
|
||||
std::vector<bool> _tabStopColumns;
|
||||
bool _initDefaultTabStops = true;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Author(s):
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../input/terminalInput.hpp"
|
||||
#include "../../types/inc/IInputEvent.hpp"
|
||||
#include "../../buffer/out/LineRendition.hpp"
|
||||
#include "../../buffer/out/TextAttribute.hpp"
|
||||
|
@ -46,9 +47,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
size_t& eventsWritten) = 0;
|
||||
virtual bool SetConsoleWindowInfo(const bool absolute,
|
||||
const SMALL_RECT& window) = 0;
|
||||
virtual bool PrivateSetCursorKeysMode(const bool applicationMode) = 0;
|
||||
virtual bool PrivateSetKeypadMode(const bool applicationMode) = 0;
|
||||
virtual bool PrivateEnableWin32InputMode(const bool win32InputMode) = 0;
|
||||
|
||||
virtual bool SetInputMode(const TerminalInput::Mode mode, const bool enabled) = 0;
|
||||
|
||||
virtual bool PrivateSetAnsiMode(const bool ansiMode) = 0;
|
||||
virtual bool PrivateSetScreenMode(const bool reverseMode) = 0;
|
||||
|
@ -66,12 +66,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
virtual bool PrivateUseAlternateScreenBuffer() = 0;
|
||||
virtual bool PrivateUseMainScreenBuffer() = 0;
|
||||
|
||||
virtual bool PrivateEnableVT200MouseMode(const bool enabled) = 0;
|
||||
virtual bool PrivateEnableUTF8ExtendedMouseMode(const bool enabled) = 0;
|
||||
virtual bool PrivateEnableSGRExtendedMouseMode(const bool enabled) = 0;
|
||||
virtual bool PrivateEnableButtonEventMouseMode(const bool enabled) = 0;
|
||||
virtual bool PrivateEnableAnyEventMouseMode(const bool enabled) = 0;
|
||||
virtual bool PrivateEnableAlternateScroll(const bool enabled) = 0;
|
||||
virtual bool PrivateEraseAll() = 0;
|
||||
virtual bool PrivateClearBuffer() = 0;
|
||||
virtual bool GetUserDefaultCursorStyle(CursorType& style) = 0;
|
||||
|
|
|
@ -298,7 +298,7 @@ public:
|
|||
s_pwszInputExpected = L"\x0";
|
||||
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
||||
|
||||
mouseInput->EnableDefaultTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
||||
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
|
@ -318,7 +318,7 @@ public:
|
|||
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
||||
}
|
||||
|
||||
mouseInput->EnableButtonEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -337,7 +337,7 @@ public:
|
|||
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
||||
}
|
||||
|
||||
mouseInput->EnableAnyEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -381,11 +381,11 @@ public:
|
|||
s_pwszInputExpected = L"\x0";
|
||||
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
||||
|
||||
mouseInput->SetUtf8ExtendedMode(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true);
|
||||
|
||||
short MaxCoord = SHORT_MAX - 33;
|
||||
|
||||
mouseInput->EnableDefaultTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -404,7 +404,7 @@ public:
|
|||
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
||||
}
|
||||
|
||||
mouseInput->EnableButtonEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -423,7 +423,7 @@ public:
|
|||
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
||||
}
|
||||
|
||||
mouseInput->EnableAnyEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -467,13 +467,13 @@ public:
|
|||
s_pwszInputExpected = L"\x0";
|
||||
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
||||
|
||||
mouseInput->SetSGRExtendedMode(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::SgrMouseEncoding, true);
|
||||
|
||||
// SGR Mode should be able to handle any arbitrary coords.
|
||||
// However, mouse moves are only handled in Any Event mode
|
||||
fExpectedKeyHandled = uiButton != WM_MOUSEMOVE;
|
||||
|
||||
mouseInput->EnableDefaultTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -487,7 +487,7 @@ public:
|
|||
NoThrowString().Format(L"(x,y)=(%d,%d)", Coord.X, Coord.Y));
|
||||
}
|
||||
|
||||
mouseInput->EnableButtonEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -506,7 +506,7 @@ public:
|
|||
}
|
||||
|
||||
fExpectedKeyHandled = true;
|
||||
mouseInput->EnableAnyEventTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true);
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
COORD Coord = s_rgTestCoords[i];
|
||||
|
@ -550,7 +550,7 @@ public:
|
|||
VERIFY_ARE_EQUAL(fExpectedKeyHandled, mouseInput->HandleMouse({ 0, 0 }, uiButton, sModifierKeystate, sScrollDelta, {}));
|
||||
|
||||
// Default Tracking, Default Encoding
|
||||
mouseInput->EnableDefaultTracking(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true);
|
||||
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
|
@ -571,7 +571,7 @@ public:
|
|||
}
|
||||
|
||||
// Default Tracking, UTF8 Encoding
|
||||
mouseInput->SetUtf8ExtendedMode(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true);
|
||||
short MaxCoord = SHORT_MAX - 33;
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
|
@ -592,7 +592,7 @@ public:
|
|||
}
|
||||
|
||||
// Default Tracking, SGR Encoding
|
||||
mouseInput->SetSGRExtendedMode(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::SgrMouseEncoding, true);
|
||||
fExpectedKeyHandled = true; // SGR Mode should be able to handle any arbitrary coords.
|
||||
for (int i = 0; i < s_iTestCoordsLength; i++)
|
||||
{
|
||||
|
@ -620,7 +620,7 @@ public:
|
|||
|
||||
Log::Comment(L"Enable alternate scroll mode in the alt screen buffer");
|
||||
mouseInput->UseAlternateScreenBuffer();
|
||||
mouseInput->EnableAlternateScroll(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, true);
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling up");
|
||||
s_pwszInputExpected = L"\x1B[A";
|
||||
|
@ -631,7 +631,7 @@ public:
|
|||
VERIFY_IS_TRUE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, -WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Enable cursor keys mode");
|
||||
mouseInput->ChangeCursorKeysMode(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::CursorKey, true);
|
||||
|
||||
Log::Comment(L"Test mouse wheel scrolling up");
|
||||
s_pwszInputExpected = L"\x1BOA";
|
||||
|
@ -643,12 +643,12 @@ public:
|
|||
|
||||
Log::Comment(L"Confirm no effect when scroll mode is disabled");
|
||||
mouseInput->UseAlternateScreenBuffer();
|
||||
mouseInput->EnableAlternateScroll(false);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, false);
|
||||
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
||||
|
||||
Log::Comment(L"Confirm no effect when using the main buffer");
|
||||
mouseInput->UseMainScreenBuffer();
|
||||
mouseInput->EnableAlternateScroll(true);
|
||||
mouseInput->SetInputMode(TerminalInput::Mode::AlternateScroll, true);
|
||||
VERIFY_IS_FALSE(mouseInput->HandleMouse({ 0, 0 }, WM_MOUSEWHEEL, noModifierKeys, WHEEL_DELTA, {}));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -112,35 +112,17 @@ public:
|
|||
return _setConsoleWindowInfoResult;
|
||||
}
|
||||
|
||||
bool PrivateSetCursorKeysMode(const bool applicationMode) override
|
||||
bool SetInputMode(const TerminalInput::Mode mode, const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateSetCursorKeysMode MOCK called...");
|
||||
Log::Comment(L"SetInputMode MOCK called...");
|
||||
|
||||
if (_privateSetCursorKeysModeResult)
|
||||
if (_setInputModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_cursorKeysApplicationMode, applicationMode);
|
||||
VERIFY_ARE_EQUAL(_expectedInputMode, mode);
|
||||
VERIFY_ARE_EQUAL(_expectedInputModeEnabled, enabled);
|
||||
}
|
||||
|
||||
return _privateSetCursorKeysModeResult;
|
||||
}
|
||||
|
||||
bool PrivateSetKeypadMode(const bool applicationMode) override
|
||||
{
|
||||
Log::Comment(L"PrivateSetKeypadMode MOCK called...");
|
||||
|
||||
if (_privateSetKeypadModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_keypadApplicationMode, applicationMode);
|
||||
}
|
||||
|
||||
return _privateSetKeypadModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableWin32InputMode(const bool /*win32InputMode*/) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableWin32InputMode MOCK called...");
|
||||
|
||||
return true;
|
||||
return _setInputModeResult;
|
||||
}
|
||||
|
||||
bool PrivateSetAnsiMode(const bool ansiMode) override
|
||||
|
@ -352,66 +334,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PrivateEnableVT200MouseMode(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableVT200MouseMode MOCK called...");
|
||||
if (_privateEnableVT200MouseModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedMouseEnabled, enabled);
|
||||
}
|
||||
return _privateEnableVT200MouseModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableUTF8ExtendedMouseMode(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableUTF8ExtendedMouseMode MOCK called...");
|
||||
if (_privateEnableUTF8ExtendedMouseModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedMouseEnabled, enabled);
|
||||
}
|
||||
return _privateEnableUTF8ExtendedMouseModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableSGRExtendedMouseMode(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableSGRExtendedMouseMode MOCK called...");
|
||||
if (_privateEnableSGRExtendedMouseModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedMouseEnabled, enabled);
|
||||
}
|
||||
return _privateEnableSGRExtendedMouseModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableButtonEventMouseMode(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableButtonEventMouseMode MOCK called...");
|
||||
if (_privateEnableButtonEventMouseModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedMouseEnabled, enabled);
|
||||
}
|
||||
return _privateEnableButtonEventMouseModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableAnyEventMouseMode(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableAnyEventMouseMode MOCK called...");
|
||||
if (_privateEnableAnyEventMouseModeResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedMouseEnabled, enabled);
|
||||
}
|
||||
return _privateEnableAnyEventMouseModeResult;
|
||||
}
|
||||
|
||||
bool PrivateEnableAlternateScroll(const bool enabled) override
|
||||
{
|
||||
Log::Comment(L"PrivateEnableAlternateScroll MOCK called...");
|
||||
if (_privateEnableAlternateScrollResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedAlternateScrollEnabled, enabled);
|
||||
}
|
||||
return _privateEnableAlternateScrollResult;
|
||||
}
|
||||
|
||||
bool PrivateEraseAll() override
|
||||
{
|
||||
Log::Comment(L"PrivateEraseAll MOCK called...");
|
||||
|
@ -787,10 +709,9 @@ public:
|
|||
|
||||
COORD _expectedScreenBufferSize = { 0, 0 };
|
||||
SMALL_RECT _expectedScreenBufferViewport{ 0, 0, 0, 0 };
|
||||
bool _privateSetCursorKeysModeResult = false;
|
||||
bool _privateSetKeypadModeResult = false;
|
||||
bool _cursorKeysApplicationMode = false;
|
||||
bool _keypadApplicationMode = false;
|
||||
bool _setInputModeResult = false;
|
||||
TerminalInput::Mode _expectedInputMode;
|
||||
bool _expectedInputModeEnabled = false;
|
||||
bool _privateSetAnsiModeResult = false;
|
||||
bool _expectedAnsiMode = false;
|
||||
bool _privateAllowCursorBlinkingResult = false;
|
||||
|
@ -803,14 +724,6 @@ public:
|
|||
|
||||
bool _setConsoleTitleWResult = false;
|
||||
std::wstring_view _expectedWindowTitle{};
|
||||
bool _expectedMouseEnabled = false;
|
||||
bool _expectedAlternateScrollEnabled = false;
|
||||
bool _privateEnableVT200MouseModeResult = false;
|
||||
bool _privateEnableUTF8ExtendedMouseModeResult = false;
|
||||
bool _privateEnableSGRExtendedMouseModeResult = false;
|
||||
bool _privateEnableButtonEventMouseModeResult = false;
|
||||
bool _privateEnableAnyEventMouseModeResult = false;
|
||||
bool _privateEnableAlternateScrollResult = false;
|
||||
bool _setCursorStyleResult = false;
|
||||
CursorType _expectedCursorStyle;
|
||||
bool _setCursorColorResult = false;
|
||||
|
@ -2100,15 +2013,17 @@ public:
|
|||
// success cases
|
||||
// set numeric mode = true
|
||||
Log::Comment(L"Test 1: application mode = false");
|
||||
_testGetSet->_privateSetCursorKeysModeResult = TRUE;
|
||||
_testGetSet->_cursorKeysApplicationMode = false;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::CursorKey;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->SetCursorKeysMode(false));
|
||||
|
||||
// set numeric mode = false
|
||||
Log::Comment(L"Test 2: application mode = true");
|
||||
_testGetSet->_privateSetCursorKeysModeResult = TRUE;
|
||||
_testGetSet->_cursorKeysApplicationMode = true;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::CursorKey;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->SetCursorKeysMode(true));
|
||||
}
|
||||
|
@ -2120,15 +2035,17 @@ public:
|
|||
// success cases
|
||||
// set numeric mode = true
|
||||
Log::Comment(L"Test 1: application mode = false");
|
||||
_testGetSet->_privateSetKeypadModeResult = TRUE;
|
||||
_testGetSet->_keypadApplicationMode = false;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::Keypad;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->SetKeypadMode(false));
|
||||
|
||||
// set numeric mode = false
|
||||
Log::Comment(L"Test 2: application mode = true");
|
||||
_testGetSet->_privateSetKeypadModeResult = TRUE;
|
||||
_testGetSet->_keypadApplicationMode = true;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::Keypad;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->SetKeypadMode(true));
|
||||
}
|
||||
|
@ -2316,45 +2233,51 @@ public:
|
|||
Log::Comment(L"Starting test...");
|
||||
|
||||
Log::Comment(L"Test 1: Test Default Mouse Mode");
|
||||
_testGetSet->_expectedMouseEnabled = true;
|
||||
_testGetSet->_privateEnableVT200MouseModeResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::DefaultMouseTracking;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableVT200MouseMode(true));
|
||||
_testGetSet->_expectedMouseEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableVT200MouseMode(false));
|
||||
|
||||
Log::Comment(L"Test 2: Test UTF-8 Extended Mouse Mode");
|
||||
_testGetSet->_expectedMouseEnabled = true;
|
||||
_testGetSet->_privateEnableUTF8ExtendedMouseModeResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::Utf8MouseEncoding;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableUTF8ExtendedMouseMode(true));
|
||||
_testGetSet->_expectedMouseEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableUTF8ExtendedMouseMode(false));
|
||||
|
||||
Log::Comment(L"Test 3: Test SGR Extended Mouse Mode");
|
||||
_testGetSet->_expectedMouseEnabled = true;
|
||||
_testGetSet->_privateEnableSGRExtendedMouseModeResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::SgrMouseEncoding;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableSGRExtendedMouseMode(true));
|
||||
_testGetSet->_expectedMouseEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableSGRExtendedMouseMode(false));
|
||||
|
||||
Log::Comment(L"Test 4: Test Button-Event Mouse Mode");
|
||||
_testGetSet->_expectedMouseEnabled = true;
|
||||
_testGetSet->_privateEnableButtonEventMouseModeResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::ButtonEventMouseTracking;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableButtonEventMouseMode(true));
|
||||
_testGetSet->_expectedMouseEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableButtonEventMouseMode(false));
|
||||
|
||||
Log::Comment(L"Test 5: Test Any-Event Mouse Mode");
|
||||
_testGetSet->_expectedMouseEnabled = true;
|
||||
_testGetSet->_privateEnableAnyEventMouseModeResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::AnyEventMouseTracking;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableAnyEventMouseMode(true));
|
||||
_testGetSet->_expectedMouseEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableAnyEventMouseMode(false));
|
||||
|
||||
Log::Comment(L"Test 6: Test Alt Scroll Mouse Mode");
|
||||
_testGetSet->_expectedAlternateScrollEnabled = true;
|
||||
_testGetSet->_privateEnableAlternateScrollResult = TRUE;
|
||||
_testGetSet->_expectedInputModeEnabled = true;
|
||||
_testGetSet->_expectedInputMode = TerminalInput::Mode::AlternateScroll;
|
||||
_testGetSet->_setInputModeResult = true;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableAlternateScroll(true));
|
||||
_testGetSet->_expectedAlternateScrollEnabled = false;
|
||||
_testGetSet->_expectedInputModeEnabled = false;
|
||||
VERIFY_IS_TRUE(_pDispatch.get()->EnableAlternateScroll(false));
|
||||
}
|
||||
|
||||
|
|
|
@ -285,13 +285,13 @@ static constexpr short _encodeDefaultCoordinate(const short sCoordinateValue) no
|
|||
// - true, if we are tracking mouse input. False, otherwise
|
||||
bool TerminalInput::IsTrackingMouseInput() const noexcept
|
||||
{
|
||||
return (_mouseInputState.trackingMode != TrackingMode::None);
|
||||
return _inputMode.any(Mode::DefaultMouseTracking, Mode::ButtonEventMouseTracking, Mode::AnyEventMouseTracking);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Attempt to handle the given mouse coordinates and windows button as a VT-style mouse event.
|
||||
// If the event should be transmitted in the selected mouse mode, then we'll try and
|
||||
// encode the event according to the rules of the selected ExtendedMode, and insert those characters into the input buffer.
|
||||
// encode the event according to the rules of the encoding mode, and insert those characters into the input buffer.
|
||||
// Parameters:
|
||||
// - position - The windows coordinates (top,left = 0,0) of the mouse event
|
||||
// - button - the message to decode.
|
||||
|
@ -339,7 +339,7 @@ bool TerminalInput::HandleMouse(const COORD position,
|
|||
}
|
||||
else
|
||||
{
|
||||
success = (_mouseInputState.trackingMode != TrackingMode::None);
|
||||
success = IsTrackingMouseInput();
|
||||
if (success)
|
||||
{
|
||||
// isHover is only true for WM_MOUSEMOVE events
|
||||
|
@ -363,30 +363,23 @@ bool TerminalInput::HandleMouse(const COORD position,
|
|||
// In AnyEvent, all coord change hovers are sent
|
||||
const bool physicalButtonPressed = realButton != WM_LBUTTONUP;
|
||||
|
||||
success = (isButton && _mouseInputState.trackingMode != TrackingMode::None) ||
|
||||
(isHover && _mouseInputState.trackingMode == TrackingMode::ButtonEvent && ((!sameCoord) && (physicalButtonPressed))) ||
|
||||
(isHover && _mouseInputState.trackingMode == TrackingMode::AnyEvent && !sameCoord);
|
||||
success = (isButton && IsTrackingMouseInput()) ||
|
||||
(isHover && _inputMode.test(Mode::ButtonEventMouseTracking) && ((!sameCoord) && (physicalButtonPressed))) ||
|
||||
(isHover && _inputMode.test(Mode::AnyEventMouseTracking) && !sameCoord);
|
||||
|
||||
if (success)
|
||||
{
|
||||
std::wstring sequence;
|
||||
switch (_mouseInputState.extendedMode)
|
||||
if (_inputMode.test(Mode::Utf8MouseEncoding))
|
||||
{
|
||||
case ExtendedMode::None:
|
||||
sequence = _GenerateDefaultSequence(position,
|
||||
realButton,
|
||||
isHover,
|
||||
modifierKeyState,
|
||||
delta);
|
||||
break;
|
||||
case ExtendedMode::Utf8:
|
||||
sequence = _GenerateUtf8Sequence(position,
|
||||
realButton,
|
||||
isHover,
|
||||
modifierKeyState,
|
||||
delta);
|
||||
break;
|
||||
case ExtendedMode::Sgr:
|
||||
}
|
||||
else if (_inputMode.test(Mode::SgrMouseEncoding))
|
||||
{
|
||||
// For SGR encoding, if no physical buttons were pressed,
|
||||
// then we want to handle hovers with WM_MOUSEMOVE.
|
||||
// However, if we're dragging (WM_MOUSEMOVE with a button pressed),
|
||||
|
@ -397,13 +390,15 @@ bool TerminalInput::HandleMouse(const COORD position,
|
|||
isHover,
|
||||
modifierKeyState,
|
||||
delta);
|
||||
break;
|
||||
case ExtendedMode::Urxvt:
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
sequence = _GenerateDefaultSequence(position,
|
||||
realButton,
|
||||
isHover,
|
||||
modifierKeyState,
|
||||
delta);
|
||||
}
|
||||
success = !sequence.empty();
|
||||
|
||||
if (success)
|
||||
|
@ -411,7 +406,7 @@ bool TerminalInput::HandleMouse(const COORD position,
|
|||
_SendInputSequence(sequence);
|
||||
success = true;
|
||||
}
|
||||
if (_mouseInputState.trackingMode == TrackingMode::ButtonEvent || _mouseInputState.trackingMode == TrackingMode::AnyEvent)
|
||||
if (_inputMode.any(Mode::ButtonEventMouseTracking, Mode::AnyEventMouseTracking))
|
||||
{
|
||||
_mouseInputState.lastPos.X = position.X;
|
||||
_mouseInputState.lastPos.Y = position.Y;
|
||||
|
@ -547,10 +542,10 @@ std::wstring TerminalInput::_GenerateSGRSequence(const COORD position,
|
|||
// - delta: The scroll wheel delta of the input event
|
||||
// Return value:
|
||||
// True iff the alternate buffer is active and alternate scroll mode is enabled and the event is a mouse wheel event.
|
||||
bool TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept
|
||||
bool TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const
|
||||
{
|
||||
return _mouseInputState.inAlternateBuffer &&
|
||||
_mouseInputState.alternateScroll &&
|
||||
_inputMode.test(Mode::AlternateScroll) &&
|
||||
(button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0;
|
||||
}
|
||||
|
||||
|
@ -560,15 +555,15 @@ bool TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const
|
|||
// - delta: The scroll wheel delta of the input event
|
||||
// Return value:
|
||||
// True iff the input sequence was sent successfully.
|
||||
bool TerminalInput::_SendAlternateScroll(const short delta) const noexcept
|
||||
bool TerminalInput::_SendAlternateScroll(const short delta) const
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
_SendInputSequence(_cursorApplicationMode ? ApplicationUpSequence : CursorUpSequence);
|
||||
_SendInputSequence(_inputMode.test(Mode::CursorKey) ? ApplicationUpSequence : CursorUpSequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
_SendInputSequence(_cursorApplicationMode ? ApplicationDownSequence : CursorDownSequence);
|
||||
_SendInputSequence(_inputMode.test(Mode::CursorKey) ? ApplicationDownSequence : CursorDownSequence);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,91 +7,6 @@
|
|||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
// Routine Description:
|
||||
// - Either enables or disables UTF-8 extended mode encoding. This *should* cause
|
||||
// the coordinates of a mouse event to be encoded as a UTF-8 byte stream, however, because windows' input is
|
||||
// typically UTF-16 encoded, it emits a UTF-16 stream.
|
||||
// Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals.
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::SetUtf8ExtendedMode(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.extendedMode = enable ? ExtendedMode::Utf8 : ExtendedMode::None;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Either enables or disables SGR extended mode encoding. This causes the
|
||||
// coordinates of a mouse event to be emitted in a human readable format,
|
||||
// eg, x,y=203,504 -> "^[[<B;203;504M". This way, applications don't need to worry about character encoding.
|
||||
// Does NOT enable or disable mouse mode by itself. This matches the behavior I found in Ubuntu terminals.
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::SetSGRExtendedMode(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.extendedMode = enable ? ExtendedMode::Sgr : ExtendedMode::None;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Either enables or disables mouse mode handling. Leaves the extended mode alone,
|
||||
// so if we disable then re-enable mouse mode without toggling an extended mode, the mode will persist.
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::EnableDefaultTracking(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.trackingMode = enable ? TrackingMode::Default : TrackingMode::None;
|
||||
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
|
||||
_mouseInputState.lastButton = 0;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Either enables or disables ButtonEvent mouse handling. Button Event mode
|
||||
// sends additional sequences when a button is pressed and the mouse changes character cells.
|
||||
// Leaves the extended mode alone, so if we disable then re-enable mouse mode
|
||||
// without toggling an extended mode, the mode will persist.
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::EnableButtonEventTracking(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None;
|
||||
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
|
||||
_mouseInputState.lastButton = 0;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Either enables or disables AnyEvent mouse handling. Any Event mode sends sequences
|
||||
// for any and every mouse event, regardless if a button is pressed or not.
|
||||
// Leaves the extended mode alone, so if we disable then re-enable mouse mode
|
||||
// without toggling an extended mode, the mode will persist.
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::EnableAnyEventTracking(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None;
|
||||
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
|
||||
_mouseInputState.lastButton = 0;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Enables alternate scroll mode. This sends Cursor Up/down sequences when in the alternate buffer
|
||||
// Parameters:
|
||||
// - enable - either enable or disable.
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::EnableAlternateScroll(const bool enable) noexcept
|
||||
{
|
||||
_mouseInputState.alternateScroll = enable;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer
|
||||
// Parameters:
|
||||
|
|
|
@ -250,25 +250,32 @@ const wchar_t* const CTRL_QUESTIONMARK_SEQUENCE = L"\x7F";
|
|||
const wchar_t* const CTRL_ALT_SLASH_SEQUENCE = L"\x1b\x1f";
|
||||
const wchar_t* const CTRL_ALT_QUESTIONMARK_SEQUENCE = L"\x1b\x7F";
|
||||
|
||||
void TerminalInput::ChangeAnsiMode(const bool ansiMode) noexcept
|
||||
void TerminalInput::SetInputMode(const Mode mode, const bool enabled)
|
||||
{
|
||||
_ansiMode = ansiMode;
|
||||
// If we're changing a tracking mode, we always clear other tracking modes first.
|
||||
// We also clear out the last saved mouse position & button.
|
||||
if (mode == Mode::DefaultMouseTracking || mode == Mode::ButtonEventMouseTracking || mode == Mode::AnyEventMouseTracking)
|
||||
{
|
||||
_inputMode.reset_all(Mode::DefaultMouseTracking, Mode::ButtonEventMouseTracking, Mode::AnyEventMouseTracking);
|
||||
_mouseInputState.lastPos = { -1, -1 };
|
||||
_mouseInputState.lastButton = 0;
|
||||
}
|
||||
|
||||
// But if we're changing the encoding, we only clear out the other encoding modes
|
||||
// when enabling a new encoding - not when disabling.
|
||||
if ((mode == Mode::Utf8MouseEncoding || mode == Mode::SgrMouseEncoding) && enabled)
|
||||
{
|
||||
_inputMode.reset_all(Mode::Utf8MouseEncoding, Mode::SgrMouseEncoding);
|
||||
}
|
||||
|
||||
_inputMode.set(mode, enabled);
|
||||
}
|
||||
|
||||
void TerminalInput::ChangeKeypadMode(const bool applicationMode) noexcept
|
||||
bool TerminalInput::GetInputMode(const Mode mode) const
|
||||
{
|
||||
_keypadApplicationMode = applicationMode;
|
||||
return _inputMode.test(mode);
|
||||
}
|
||||
|
||||
void TerminalInput::ChangeCursorKeysMode(const bool applicationMode) noexcept
|
||||
{
|
||||
_cursorApplicationMode = applicationMode;
|
||||
}
|
||||
|
||||
void TerminalInput::ChangeWin32InputMode(const bool win32InputMode) noexcept
|
||||
{
|
||||
_win32InputMode = win32InputMode;
|
||||
}
|
||||
void TerminalInput::ForceDisableWin32InputMode(const bool win32InputMode) noexcept
|
||||
{
|
||||
_forceDisableWin32InputMode = win32InputMode;
|
||||
|
@ -530,7 +537,7 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent)
|
|||
// GH#4999 - If we're in win32-input mode, skip straight to doing that.
|
||||
// Since this mode handles all types of key events, do nothing else.
|
||||
// Only do this if win32-input-mode support isn't manually disabled.
|
||||
if (_win32InputMode && !_forceDisableWin32InputMode)
|
||||
if (_inputMode.test(Mode::Win32) && !_forceDisableWin32InputMode)
|
||||
{
|
||||
const auto seq = _GenerateWin32KeySequence(keyEvent);
|
||||
_SendInputSequence(seq);
|
||||
|
@ -655,7 +662,7 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent)
|
|||
// Check any other key mappings (like those for the F1-F12 keys).
|
||||
// These mappings will kick in no matter which modifiers are pressed and as such
|
||||
// must be checked last, or otherwise we'd override more complex key combinations.
|
||||
const auto mapping = _getKeyMapping(keyEvent, _ansiMode, _cursorApplicationMode, _keypadApplicationMode);
|
||||
const auto mapping = _getKeyMapping(keyEvent, _inputMode.test(Mode::Ansi), _inputMode.test(Mode::CursorKey), _inputMode.test(Mode::Keypad));
|
||||
if (_translateDefaultMapping(keyEvent, mapping, senderFunc))
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -34,11 +34,26 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
~TerminalInput() = default;
|
||||
|
||||
bool HandleKey(const IInputEvent* const pInEvent);
|
||||
void ChangeAnsiMode(const bool ansiMode) noexcept;
|
||||
void ChangeKeypadMode(const bool applicationMode) noexcept;
|
||||
void ChangeCursorKeysMode(const bool applicationMode) noexcept;
|
||||
|
||||
void ChangeWin32InputMode(const bool win32InputMode) noexcept;
|
||||
enum class Mode : size_t
|
||||
{
|
||||
Ansi,
|
||||
Keypad,
|
||||
CursorKey,
|
||||
Win32,
|
||||
|
||||
Utf8MouseEncoding,
|
||||
SgrMouseEncoding,
|
||||
|
||||
DefaultMouseTracking,
|
||||
ButtonEventMouseTracking,
|
||||
AnyEventMouseTracking,
|
||||
|
||||
AlternateScroll
|
||||
};
|
||||
|
||||
void SetInputMode(const Mode mode, const bool enabled);
|
||||
bool GetInputMode(const Mode mode) const;
|
||||
void ForceDisableWin32InputMode(const bool win32InputMode) noexcept;
|
||||
|
||||
#pragma region MouseInput
|
||||
|
@ -62,14 +77,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
#pragma region MouseInputState Management
|
||||
// These methods are defined in mouseInputState.cpp
|
||||
void SetUtf8ExtendedMode(const bool enable) noexcept;
|
||||
void SetSGRExtendedMode(const bool enable) noexcept;
|
||||
|
||||
void EnableDefaultTracking(const bool enable) noexcept;
|
||||
void EnableButtonEventTracking(const bool enable) noexcept;
|
||||
void EnableAnyEventTracking(const bool enable) noexcept;
|
||||
|
||||
void EnableAlternateScroll(const bool enable) noexcept;
|
||||
void UseAlternateScreenBuffer() noexcept;
|
||||
void UseMainScreenBuffer() noexcept;
|
||||
#pragma endregion
|
||||
|
@ -80,10 +87,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
std::optional<wchar_t> _leadingSurrogate;
|
||||
|
||||
bool _ansiMode{ true };
|
||||
bool _keypadApplicationMode{ false };
|
||||
bool _cursorApplicationMode{ false };
|
||||
bool _win32InputMode{ false };
|
||||
til::enumset<Mode> _inputMode{ Mode::Ansi };
|
||||
bool _forceDisableWin32InputMode{ false };
|
||||
|
||||
void _SendChar(const wchar_t ch);
|
||||
|
@ -94,27 +98,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
#pragma region MouseInputState Management
|
||||
// These methods are defined in mouseInputState.cpp
|
||||
enum class ExtendedMode : unsigned int
|
||||
{
|
||||
None,
|
||||
Utf8,
|
||||
Sgr,
|
||||
Urxvt
|
||||
};
|
||||
|
||||
enum class TrackingMode : unsigned int
|
||||
{
|
||||
None,
|
||||
Default,
|
||||
ButtonEvent,
|
||||
AnyEvent
|
||||
};
|
||||
|
||||
struct MouseInputState
|
||||
{
|
||||
ExtendedMode extendedMode{ ExtendedMode::None };
|
||||
TrackingMode trackingMode{ TrackingMode::None };
|
||||
bool alternateScroll{ false };
|
||||
bool inAlternateBuffer{ false };
|
||||
COORD lastPos{ -1, -1 };
|
||||
unsigned int lastButton{ 0 };
|
||||
|
@ -142,8 +127,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
const short modifierKeyState,
|
||||
const short delta);
|
||||
|
||||
bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
|
||||
bool _SendAlternateScroll(const short delta) const noexcept;
|
||||
bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const;
|
||||
bool _SendAlternateScroll(const short delta) const;
|
||||
|
||||
static constexpr unsigned int s_GetPressedButton(const MouseButtonState state) noexcept;
|
||||
#pragma endregion
|
||||
|
|
|
@ -1101,22 +1101,22 @@ bool OutputStateMachineEngine::_GetOscSetClipboard(const std::wstring_view strin
|
|||
std::wstring& content,
|
||||
bool& queryClipboard) const noexcept
|
||||
{
|
||||
const size_t pos = string.find(';');
|
||||
if (pos != std::wstring_view::npos)
|
||||
const auto pos = string.find(L';');
|
||||
if (pos == std::wstring_view::npos)
|
||||
{
|
||||
const std::wstring_view substr = string.substr(pos + 1);
|
||||
if (substr == L"?")
|
||||
{
|
||||
queryClipboard = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Base64::s_Decode(substr, content);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
const auto substr = string.substr(pos + 1);
|
||||
if (substr == L"?")
|
||||
{
|
||||
queryClipboard = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log_IfFailed has the following description: "Should be decorated WI_NOEXCEPT, but conflicts with forceinline."
|
||||
#pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function 'Log_IfFailed()' which may throw exceptions (f.6).
|
||||
return SUCCEEDED_LOG(Base64::Decode(substr, content));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -4,190 +4,155 @@
|
|||
#include "precomp.h"
|
||||
#include "base64.hpp"
|
||||
|
||||
#pragma warning(disable : 26446) // Prefer to use gsl::at() instead of unchecked subscript operator (bounds.4).
|
||||
// I didn't want to handle out of memory errors. There's no reasonable mode of
|
||||
// operation for this application without the ability to allocate memory anyways.
|
||||
#pragma warning(disable : 26447) // The function is declared 'noexcept' but calls function '...' which may throw exceptions (f.6).
|
||||
#pragma warning(disable : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
|
||||
#pragma warning(disable : 26482) // Only index into arrays using constant expressions (bounds.2).
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
static const char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char padChar = '=';
|
||||
// clang-format off
|
||||
static constexpr uint8_t decodeTable[128] = {
|
||||
255 /* NUL */, 255 /* SOH */, 255 /* STX */, 255 /* ETX */, 255 /* EOT */, 255 /* ENQ */, 255 /* ACK */, 255 /* BEL */, 255 /* BS */, 255 /* HT */, 255 /* LF */, 255 /* VT */, 255 /* FF */, 255 /* CR */, 255 /* SO */, 255 /* SI */,
|
||||
255 /* DLE */, 255 /* DC1 */, 255 /* DC2 */, 255 /* DC3 */, 255 /* DC4 */, 255 /* NAK */, 255 /* SYN */, 255 /* ETB */, 255 /* CAN */, 255 /* EM */, 255 /* SUB */, 255 /* ESC */, 255 /* FS */, 255 /* GS */, 255 /* RS */, 255 /* US */,
|
||||
255 /* SP */, 255 /* ! */, 255 /* " */, 255 /* # */, 255 /* $ */, 255 /* % */, 255 /* & */, 255 /* ' */, 255 /* ( */, 255 /* ) */, 255 /* * */, 62 /* + */, 255 /* , */, 62 /* - */, 255 /* . */, 63 /* / */,
|
||||
52 /* 0 */, 53 /* 1 */, 54 /* 2 */, 55 /* 3 */, 56 /* 4 */, 57 /* 5 */, 58 /* 6 */, 59 /* 7 */, 60 /* 8 */, 61 /* 9 */, 255 /* : */, 255 /* ; */, 255 /* < */, 255 /* = */, 255 /* > */, 255 /* ? */,
|
||||
255 /* @ */, 0 /* A */, 1 /* B */, 2 /* C */, 3 /* D */, 4 /* E */, 5 /* F */, 6 /* G */, 7 /* H */, 8 /* I */, 9 /* J */, 10 /* K */, 11 /* L */, 12 /* M */, 13 /* N */, 14 /* O */,
|
||||
15 /* P */, 16 /* Q */, 17 /* R */, 18 /* S */, 19 /* T */, 20 /* U */, 21 /* V */, 22 /* W */, 23 /* X */, 24 /* Y */, 25 /* Z */, 255 /* [ */, 255 /* \ */, 255 /* ] */, 255 /* ^ */, 63 /* _ */,
|
||||
255 /* ` */, 26 /* a */, 27 /* b */, 28 /* c */, 29 /* d */, 30 /* e */, 31 /* f */, 32 /* g */, 33 /* h */, 34 /* i */, 35 /* j */, 36 /* k */, 37 /* l */, 38 /* m */, 39 /* n */, 40 /* o */,
|
||||
41 /* p */, 42 /* q */, 43 /* r */, 44 /* s */, 45 /* t */, 46 /* u */, 47 /* v */, 48 /* w */, 49 /* x */, 50 /* y */, 51 /* z */, 255 /* { */, 255 /* | */, 255 /* } */, 255 /* ~ */, 255 /* DEL */,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#pragma warning(disable : 26446 26447 26482 26485 26493 26494)
|
||||
|
||||
// Routine Description:
|
||||
// - Encode a string using base64. When there are not enough characters
|
||||
// for one quantum, paddings are added.
|
||||
// Arguments:
|
||||
// - src - String to base64 encode.
|
||||
// Return Value:
|
||||
// - the encoded string.
|
||||
std::wstring Base64::s_Encode(const std::wstring_view src) noexcept
|
||||
// Decodes an UTF8 string encoded with RFC 4648 (Base64) and returns it as UTF16 in dst.
|
||||
// It supports both variants of the RFC (base64 and base64url), but
|
||||
// throws an error for non-alphabet characters, including newlines.
|
||||
// * Throws an exception for all invalid base64 inputs.
|
||||
// * Doesn't support whitespace and will throw an exception for such strings.
|
||||
// * Doesn't validate the number of trailing "=". Those are basically ignored.
|
||||
// Strings like "YQ===" will be accepted as valid input and simply result in "a".
|
||||
HRESULT Base64::Decode(const std::wstring_view& src, std::wstring& dst) noexcept
|
||||
{
|
||||
std::wstring dst;
|
||||
wchar_t input[3];
|
||||
std::string result;
|
||||
result.resize(((src.size() + 3) / 4) * 3);
|
||||
|
||||
const auto len = (src.size() + 2) / 3 * 4;
|
||||
if (len == 0)
|
||||
{
|
||||
return dst;
|
||||
}
|
||||
dst.reserve(len);
|
||||
// in and inEnd may be nullptr if src.empty().
|
||||
// The remaining code in this function ensures not to read from in if src.empty().
|
||||
#pragma warning(suppress : 26429) // Symbol 'in' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto in = src.data();
|
||||
const auto inEnd = in + src.size();
|
||||
// Sometimes in programming you have to ask yourself what the right offset for a pointer is.
|
||||
// Is 4 enough? Certainly not. 6 on the other hand is just way too much. Clearly 5 is just right.
|
||||
//
|
||||
// In all seriousness however the offset is 5, because the batched loop reads 4 characters at a time,
|
||||
// a base64 string can end with two "=" and the batched loop doesn't handle any such "=".
|
||||
// Additionally the while() condition of the batched loop would make a lot more sense if it were using <=,
|
||||
// but for reasons outlined below it needs to use < so we need to add 1 back again.
|
||||
// We thus get -4-2+1 which is -5.
|
||||
//
|
||||
// There's a special reason we need to use < and not <= for the loop:
|
||||
// In C++ it's undefined behavior to perform any pointer arithmetic that leads to unallocated memory,
|
||||
// which is why we can't just write `inEnd - 6` as that might be UB if `src.size()` is less than 6.
|
||||
// We thus would need write `inEnd - min(6, src.size())` in combination with `<=` for the batched loop.
|
||||
// But if `src.size()` is actually less than 6 then `inEnd` is equal to the initial `in`, aka: an empty range.
|
||||
// In such cases we'd enter the batched loop and read from `in` despite us not wanting to enter the loop.
|
||||
// We can fix the issue by using < instead and adding +1 to the offset.
|
||||
//
|
||||
// Yes this works.
|
||||
const auto inEndBatched = inEnd - std::min<size_t>(5, src.size());
|
||||
|
||||
auto iter = src.cbegin();
|
||||
// Encode each three chars into one quantum (four chars).
|
||||
while (iter < src.cend() - 2)
|
||||
// outBeg and out may be nullptr if src.empty().
|
||||
// The remaining code in this function ensures not to write to out if src.empty().
|
||||
const auto outBeg = result.data();
|
||||
#pragma warning(suppress : 26429) // Symbol 'out' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto out = outBeg;
|
||||
|
||||
// r is just a generic "remainder" we use to accumulate 4 base64 chars into 3 output bytes.
|
||||
uint_fast32_t r = 0;
|
||||
// error is treated as a boolean. If it's not 0 we had an invalid input character.
|
||||
uint_fast16_t error = 0;
|
||||
|
||||
// Capturing r/error by reference produces less optimal assembly.
|
||||
static constexpr auto accumulate = [](auto& r, auto& error, auto ch) {
|
||||
// n will be in the range [0, 0x3f] for valid ch
|
||||
// and exactly 0xff for invalid ch.
|
||||
const auto n = decodeTable[ch & 0x7f];
|
||||
// Both ch > 0x7f, as well as n > 0x7f are invalid values and count as an error.
|
||||
// We can add the error state by checking if any bits ~0x7f are set (which is 0xff80).
|
||||
error |= (ch | n) & 0xff80;
|
||||
r = r << 6 | n;
|
||||
};
|
||||
|
||||
// If src.empty() then `in == inEndBatched == nullptr` and this is skipped.
|
||||
while (in < inEndBatched)
|
||||
{
|
||||
input[0] = *iter++;
|
||||
input[1] = *iter++;
|
||||
input[2] = *iter++;
|
||||
dst.push_back(base64Chars[input[0] >> 2]);
|
||||
dst.push_back(base64Chars[(input[0] & 0x03) << 4 | input[1] >> 4]);
|
||||
dst.push_back(base64Chars[(input[1] & 0x0f) << 2 | input[2] >> 6]);
|
||||
dst.push_back(base64Chars[(input[2] & 0x3f)]);
|
||||
const auto ch0 = *in++;
|
||||
const auto ch1 = *in++;
|
||||
const auto ch2 = *in++;
|
||||
const auto ch3 = *in++;
|
||||
|
||||
// Most other base64 libraries do something like this:
|
||||
// const auto n0 = decodeTable[a];
|
||||
// const auto n1 = decodeTable[b];
|
||||
// const auto n2 = decodeTable[c];
|
||||
// const auto n3 = decodeTable[d];
|
||||
// *out++ = n0 << 2 | n1 >> 4;
|
||||
// *out++ = (n1 & 0xf) << 4 | n2 >> 2;
|
||||
// *out++ = (n2 & 0x3) << 6 | n3;
|
||||
//
|
||||
// But on all modern CPUs I tested (well even those 10 years old at this point) shifting base64
|
||||
// characters into a single register (here: r) is faster than the traditional approach.
|
||||
// I believe this is due to reducing the dependency of instructions on prior calculations.
|
||||
accumulate(r, error, ch0);
|
||||
accumulate(r, error, ch1);
|
||||
accumulate(r, error, ch2);
|
||||
accumulate(r, error, ch3);
|
||||
|
||||
*out++ = gsl::narrow_cast<char>(r >> 16);
|
||||
*out++ = gsl::narrow_cast<char>(r >> 8);
|
||||
*out++ = gsl::narrow_cast<char>(r >> 0);
|
||||
}
|
||||
|
||||
// Here only zero, or one, or two chars are left. We may need to add paddings.
|
||||
if (iter < src.cend())
|
||||
{
|
||||
input[0] = *iter++;
|
||||
dst.push_back(base64Chars[input[0] >> 2]);
|
||||
if (iter < src.cend()) // Two chars left.
|
||||
uint_fast8_t ri = 0;
|
||||
|
||||
// If src.empty() then `in == inEnd == nullptr` and this is skipped.
|
||||
for (; in < inEnd; ++in)
|
||||
{
|
||||
input[1] = *iter++;
|
||||
dst.push_back(base64Chars[(input[0] & 0x03) << 4 | input[1] >> 4]);
|
||||
dst.push_back(base64Chars[(input[1] & 0x0f) << 2]);
|
||||
}
|
||||
else // Only one char left.
|
||||
{
|
||||
dst.push_back(base64Chars[(input[0] & 0x03) << 4]);
|
||||
dst.push_back(padChar);
|
||||
}
|
||||
dst.push_back(padChar);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Decode a base64 string. This requires the base64 string is properly padded.
|
||||
// Otherwise, false will be returned.
|
||||
// Arguments:
|
||||
// - src - String to decode.
|
||||
// - dst - Destination to decode into.
|
||||
// Return Value:
|
||||
// - true if decoding successfully, otherwise false.
|
||||
bool Base64::s_Decode(const std::wstring_view src, std::wstring& dst) noexcept
|
||||
{
|
||||
std::string mbStr;
|
||||
int state = 0;
|
||||
char tmp;
|
||||
|
||||
const auto len = src.size() / 4 * 3;
|
||||
if (len == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mbStr.reserve(len);
|
||||
|
||||
auto iter = src.cbegin();
|
||||
while (iter < src.cend())
|
||||
{
|
||||
if (s_IsSpace(*iter)) // Skip whitespace anywhere.
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
if (const auto ch = *in; ch != '=')
|
||||
{
|
||||
accumulate(r, error, ch);
|
||||
ri++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*iter == padChar)
|
||||
switch (ri)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto pos = strchr(base64Chars, *iter);
|
||||
if (!pos) // A non-base64 character found.
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
tmp = (char)(pos - base64Chars) << 2;
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
tmp |= (char)(pos - base64Chars) >> 4;
|
||||
mbStr += tmp;
|
||||
tmp = (char)((pos - base64Chars) & 0x0f) << 4;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
tmp |= (char)(pos - base64Chars) >> 2;
|
||||
mbStr += tmp;
|
||||
tmp = (char)((pos - base64Chars) & 0x03) << 6;
|
||||
state = 3;
|
||||
*out++ = gsl::narrow_cast<char>(r >> 4);
|
||||
break;
|
||||
case 3:
|
||||
tmp |= pos - base64Chars;
|
||||
mbStr += tmp;
|
||||
state = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
if (iter < src.cend()) // Padding char is met.
|
||||
{
|
||||
iter++;
|
||||
switch (state)
|
||||
{
|
||||
// Invalid when state is 0 or 1.
|
||||
case 0:
|
||||
case 1:
|
||||
return false;
|
||||
case 2:
|
||||
// Skip any number of spaces.
|
||||
while (iter < src.cend() && s_IsSpace(*iter))
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
// Make sure there is another trailing padding character.
|
||||
if (iter == src.cend() || *iter != padChar)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
iter++; // Skip the padding character and fallthrough to "single trailing padding character" case.
|
||||
[[fallthrough]];
|
||||
case 3:
|
||||
while (iter < src.cend())
|
||||
{
|
||||
if (!s_IsSpace(*iter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
*out++ = gsl::narrow_cast<char>(r >> 10);
|
||||
*out++ = gsl::narrow_cast<char>(r >> 2);
|
||||
break;
|
||||
case 4:
|
||||
*out++ = gsl::narrow_cast<char>(r >> 16);
|
||||
*out++ = gsl::narrow_cast<char>(r >> 8);
|
||||
*out++ = gsl::narrow_cast<char>(r >> 0);
|
||||
break;
|
||||
default:
|
||||
error |= ri;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (state != 0) // When no padding, we must be in state 0.
|
||||
|
||||
if (error)
|
||||
{
|
||||
return false;
|
||||
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
||||
}
|
||||
|
||||
return SUCCEEDED(til::u8u16(mbStr, dst));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Check if parameter is a base64 whitespace. Only carriage return or line feed
|
||||
// is valid whitespace.
|
||||
// Arguments:
|
||||
// - ch - Character to check.
|
||||
// Return Value:
|
||||
// - true iff ch is a carriage return or line feed.
|
||||
constexpr bool Base64::s_IsSpace(const wchar_t ch) noexcept
|
||||
{
|
||||
return ch == L'\r' || ch == L'\n';
|
||||
result.resize(out - outBeg);
|
||||
return til::u8u16(result, dst);
|
||||
}
|
||||
|
|
|
@ -16,10 +16,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
class Base64
|
||||
{
|
||||
public:
|
||||
static std::wstring s_Encode(const std::wstring_view src) noexcept;
|
||||
static bool s_Decode(const std::wstring_view src, std::wstring& dst) noexcept;
|
||||
|
||||
private:
|
||||
static constexpr bool s_IsSpace(const wchar_t ch) noexcept;
|
||||
static HRESULT Decode(const std::wstring_view& src, std::wstring& dst) noexcept;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
#include "../../inc/consoletaeftemplates.hpp"
|
||||
|
||||
#include <til/rand.h>
|
||||
|
||||
#include "base64.hpp"
|
||||
|
||||
|
@ -28,74 +29,90 @@ class Microsoft::Console::VirtualTerminal::Base64Test
|
|||
{
|
||||
TEST_CLASS(Base64Test);
|
||||
|
||||
TEST_METHOD(TestBase64Encode)
|
||||
TEST_METHOD(DecodeFuzz)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(L"Zm9v", Base64::s_Encode(L"foo"));
|
||||
VERIFY_ARE_EQUAL(L"Zm9vYg==", Base64::s_Encode(L"foob"));
|
||||
VERIFY_ARE_EQUAL(L"Zm9vYmE=", Base64::s_Encode(L"fooba"));
|
||||
VERIFY_ARE_EQUAL(L"Zm9vYmFy", Base64::s_Encode(L"foobar"));
|
||||
VERIFY_ARE_EQUAL(L"Zm9vYmFyDQo=", Base64::s_Encode(L"foobar\r\n"));
|
||||
// NOTE: Modify testRounds to get the feeling of running a fuzz test on Base64::Decode.
|
||||
static constexpr auto testRounds = 8;
|
||||
pcg_engines::oneseq_dxsm_64_32 rng{ til::gen_random<uint64_t>() };
|
||||
|
||||
// Fills referenceData with random ASCII characters.
|
||||
// We use ASCII as Base64::Decode uses til:u8u16 internally and I don't want to test that.
|
||||
char referenceData[128];
|
||||
{
|
||||
uint32_t randomData[sizeof(referenceData) / sizeof(uint32_t)];
|
||||
for (auto& i : randomData)
|
||||
{
|
||||
i = rng();
|
||||
}
|
||||
|
||||
const std::string_view randomDataView{ reinterpret_cast<const char*>(randomData), sizeof(randomData) };
|
||||
auto out = std::begin(referenceData);
|
||||
|
||||
for (const auto& ch : randomDataView)
|
||||
{
|
||||
*out++ = static_cast<char>(ch & 0x7f);
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t wideReferenceData[std::size(referenceData)];
|
||||
std::copy_n(std::begin(referenceData), std::size(referenceData), std::begin(wideReferenceData));
|
||||
|
||||
std::wstring encoded;
|
||||
std::wstring decoded;
|
||||
|
||||
for (auto i = 0; i < testRounds; ++i)
|
||||
{
|
||||
const auto referenceLength = rng(static_cast<uint32_t>(std::size(referenceData)));
|
||||
const std::wstring_view wideReference{ std::begin(wideReferenceData), referenceLength };
|
||||
|
||||
if (!referenceLength)
|
||||
{
|
||||
encoded.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto reference = reinterpret_cast<const BYTE*>(std::begin(referenceData));
|
||||
DWORD encodedLen;
|
||||
THROW_IF_WIN32_BOOL_FALSE(CryptBinaryToStringW(reference, referenceLength, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &encodedLen));
|
||||
|
||||
// encodedLen is returned by CryptBinaryToStringW including the trailing null byte.
|
||||
encoded.resize(encodedLen - 1);
|
||||
|
||||
THROW_IF_WIN32_BOOL_FALSE(CryptBinaryToStringW(reference, referenceLength, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, encoded.data(), &encodedLen));
|
||||
}
|
||||
|
||||
// Test whether Decode() handles strings with and without trailing "=".
|
||||
if (rng(2))
|
||||
{
|
||||
while (!encoded.empty() && encoded.back() == '=')
|
||||
{
|
||||
encoded.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Test whether Decode() handles null-pointer arguments correctly.
|
||||
std::wstring_view encodedView{ encoded };
|
||||
if (encodedView.empty() && rng(2))
|
||||
{
|
||||
encodedView = {};
|
||||
}
|
||||
|
||||
Base64::Decode(encodedView, decoded);
|
||||
VERIFY_ARE_EQUAL(wideReference, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(TestBase64Decode)
|
||||
TEST_METHOD(DecodeUTF8)
|
||||
{
|
||||
std::wstring result;
|
||||
bool success;
|
||||
|
||||
success = Base64::s_Decode(L"Zm9v", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foo", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9vYg==", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foob", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9vYmE=", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"fooba", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9vYmFy", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foobar", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9vYmFyDQo=", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foobar\r\n", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9v\rYmFy", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foobar", result);
|
||||
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"Zm9v\r\nYmFy\n", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
VERIFY_ARE_EQUAL(L"foobar", result);
|
||||
|
||||
success = Base64::s_Decode(L"Z", result);
|
||||
VERIFY_ARE_EQUAL(false, success);
|
||||
|
||||
success = Base64::s_Decode(L"Zm9vYg", result);
|
||||
VERIFY_ARE_EQUAL(false, success);
|
||||
|
||||
success = Base64::s_Decode(L"Zm9vYg=", result);
|
||||
VERIFY_ARE_EQUAL(false, success);
|
||||
|
||||
// U+306b U+307b U+3093 U+3054 U+6c49 U+8bed U+d55c U+ad6d
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"44Gr44G744KT44GU5rGJ6K+t7ZWc6rWt", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
Base64::Decode(L"44Gr44G744KT44GU5rGJ6K+t7ZWc6rWt", result);
|
||||
VERIFY_ARE_EQUAL(L"にほんご汉语한국", result);
|
||||
|
||||
// U+d83d U+dc4d U+d83d U+dc4d U+d83c U+dffb U+d83d U+dc4d U+d83c U+dffc U+d83d
|
||||
// U+dc4d U+d83c U+dffd U+d83d U+dc4d U+d83c U+dffe U+d83d U+dc4d U+d83c U+dfff
|
||||
result = L"";
|
||||
success = Base64::s_Decode(L"8J+RjfCfkY3wn4+78J+RjfCfj7zwn5GN8J+PvfCfkY3wn4++8J+RjfCfj78=", result);
|
||||
VERIFY_ARE_EQUAL(true, success);
|
||||
Base64::Decode(L"8J+RjfCfkY3wn4+78J+RjfCfj7zwn5GN8J+PvfCfkY3wn4++8J+RjfCfj78=", result);
|
||||
VERIFY_ARE_EQUAL(L"👍👍🏻👍🏼👍🏽👍🏾👍🏿", result);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3255,7 +3255,7 @@ class StateMachineExternalTest final
|
|||
|
||||
pDispatch->_copyContent = L"UNCHANGED";
|
||||
// Passing a non-base64 `Pd` param is illegal, won't change the content.
|
||||
mach.ProcessString(L"\x1b]52;;foo\x07");
|
||||
mach.ProcessString(L"\x1b]52;;???\x07");
|
||||
VERIFY_ARE_EQUAL(L"UNCHANGED", pDispatch->_copyContent);
|
||||
|
||||
pDispatch->ClearState();
|
||||
|
|
Loading…
Reference in a new issue