Compare commits
9 commits
dev/lhecke
...
main
Author | SHA1 | Date | |
---|---|---|---|
f2386de422 | |||
80f8383860 | |||
bb71179a24 | |||
df06c54e70 | |||
a98d18c030 | |||
dc01926e3e | |||
6ad848e158 | |||
ea456cf121 | |||
442432ea15 |
1
.github/actions/spelling/allow/apis.txt
vendored
1
.github/actions/spelling/allow/apis.txt
vendored
|
@ -169,6 +169,7 @@ toupper
|
|||
TTask
|
||||
TVal
|
||||
UChar
|
||||
UFIELD
|
||||
ULARGE
|
||||
UPDATEINIFILE
|
||||
userenv
|
||||
|
|
|
@ -4,7 +4,7 @@ https://www\.itscj\.ipsj\.or\.jp/iso-ir/[-0-9]+\.pdf
|
|||
https://www\.vt100\.net/docs/[-a-zA-Z0-9#_\/.]*
|
||||
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
|
||||
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
|
||||
https://(?:[a-z-]+\.|)github(?:usercontent|)\.com/[-a-zA-Z0-9?%&=_\/.]*
|
||||
https://(?:[a-z-]+\.|)github(?:usercontent|)\.com/[-a-zA-Z0-9?%&=_\/.+]*
|
||||
https://www.xfree86.org/[-a-zA-Z0-9?&=\/_#]*
|
||||
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
|
||||
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
|
||||
|
|
|
@ -99,15 +99,29 @@ If you don't have any additional info/context to add but would like to indicate
|
|||
|
||||
## Contributing fixes / features
|
||||
|
||||
For those able & willing to help fix issues and/or implement features ...
|
||||
If you're able & willing to help fix issues and/or implement features, we'd love your contribution!
|
||||
|
||||
The best place to start is the list of ["Easy Starter"](https://github.com/microsoft/terminal/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22+label%3A%22Easy+Starter%22+) issues. These are bugs or tasks that we on the team believe would be easier to implement for someone without any prior experience in the codebase. Once you're feeling more comfortable in the codebase, feel free to just use the ["Help Wanted"](https://github.com/microsoft/terminal/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22+) label, or just find an issue your interested in and hop in!
|
||||
|
||||
Generally, we categorize issues in the following way, which is largely derived from our old internal work tracking system:
|
||||
* ["Bugs"](https://github.com/microsoft/terminal/issues?q=is%3Aopen+is%3Aissue+label%3A%22Issue-Bug%22+) are parts of the Terminal & Console that are not quite working the right way. There's code to already support some scenario, but it's not quite working right. Fixing these is generally a matter of debugging the broken functionality and fixing the wrong code.
|
||||
* ["Tasks"](https://github.com/microsoft/terminal/issues?q=is%3Aopen+is%3Aissue+label%3A%22Issue-Task%22+) are usually new pieces of functionality that aren't yet implemented for the Terminal/Console. These are usually smaller features, which we believe
|
||||
- could be a single, atomic PR
|
||||
- Don't require much design consideration, or we've already written the spec for the larger feature they belong to.
|
||||
* ["Features"](https://github.com/microsoft/terminal/issues?q=is%3Aopen+is%3Aissue+label%3A%22Issue-Feature%22+) are larger pieces of new functionality. These are usually things we believe would require larger discussion of how they should be implemented, or they'll require some complicated new settings. They might just be features that are composed of many individual tasks. Often times, with features, we like to have a spec written before development work is started, to make sure we're all on the same page (see below).
|
||||
|
||||
Bugs and tasks are obviously the easiest to get started with, but don't feel afraid of features either! We've had some community members contribute some amazing "feature"-level work to the Terminal (albeit, with lots of discussion 😄).
|
||||
|
||||
|
||||
Often, we like to assign issues that generally belong to somebody's area of expertise to the team member that owns that area. This doesn't mean the community can't jump in -- they should reach out and have a chat with the assignee to see if it'd okay to take. If an issue's been assigned more than a month ago, there's a good chance it's fair game to try yourself.
|
||||
|
||||
### To Spec or not to Spec
|
||||
|
||||
Some issues/features may be quick and simple to describe and understand. For such scenarios, once a team member has agreed with your approach, skip ahead to the section headed "Fork, Branch, and Create your PR", below.
|
||||
|
||||
Small issues that do not require a spec will be labelled Issue-Bug or Issue-Task.
|
||||
Small issues that do not require a spec will be labelled `Issue-Bug` or `Issue-Task`.
|
||||
|
||||
However, some issues/features will require careful thought & formal design before implementation. For these scenarios, we'll request that a spec is written and the associated issue will be labeled Issue-Feature.
|
||||
However, some issues/features will require careful thought & formal design before implementation. For these scenarios, we'll request that a spec is written and the associated issue will be labeled `Issue-Feature`. More often than not, we'll add such features to the ["Specification Tracker" project](https://github.com/microsoft/terminal/projects/1).
|
||||
|
||||
Specs help collaborators discuss different approaches to solve a problem, describe how the feature will behave, how the feature will impact the user, what happens if something goes wrong, etc. Driving towards agreement in a spec, before any code is written, often results in simpler code, and less wasted effort in the long run.
|
||||
|
||||
|
|
|
@ -63,8 +63,14 @@
|
|||
Outputs="$(OpenConsoleCommonOutDir)\inc\TilFeatureStaging.h"
|
||||
DependsOnTargets="_GenerateBranchAndBrandingCache">
|
||||
<MakeDir Directories="$(OpenConsoleCommonOutDir)\inc" />
|
||||
<!-- This commandline is escaped like:
|
||||
|
||||
powershell -Command "&'$(SolutionDir)\tools\Generate-FeatureStagingHeader.ps1' -Path '%(FeatureFlagFile.FullPath)'' -Branding $(_WTBrandingName)"
|
||||
|
||||
which was the only way I could find to get it to obey spaces in the SolutionDir
|
||||
-->
|
||||
<Exec
|
||||
Command="powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy ByPass -Command "$(SolutionDir)\tools\Generate-FeatureStagingHeader.ps1" -Path "%(FeatureFlagFile.FullPath)" -Branding $(_WTBrandingName)"
|
||||
Command="powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy ByPass -Command "&'$(SolutionDir)\tools\Generate-FeatureStagingHeader.ps1' -Path '%(FeatureFlagFile.FullPath)' -Branding $(_WTBrandingName)""
|
||||
ConsoleToMsBuild="true"
|
||||
StandardOutputImportance="low">
|
||||
<Output TaskParameter="ConsoleOutput" ItemName="_FeatureFlagFileLines" />
|
||||
|
|
|
@ -118,6 +118,23 @@
|
|||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
BODGY
|
||||
|
||||
The wapproj `GetResolvedWinMD` target tries to get a winmd from every cppwinrt
|
||||
executable we put in the package. But we DON'T produce a winmd. This makes the
|
||||
FastUpToDate check fail every time, and leads to the whole wapproj build
|
||||
running even if you're just f5'ing the package. EVEN AFTER A SUCCESSFUL BUILD.
|
||||
|
||||
Setting GenerateWindowsMetadata=false is enough to tell the build system that
|
||||
we don't produce one, and get it off our backs.
|
||||
-->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
|
|
@ -128,22 +128,22 @@ bool TextAttribute::IsLegacy() const noexcept
|
|||
// - Calculates rgb colors based off of current color table and active modification attributes.
|
||||
// Arguments:
|
||||
// - colorTable: the current color table rgb values.
|
||||
// - defaultFgColor: the default foreground color rgb value.
|
||||
// - defaultBgColor: the default background color rgb value.
|
||||
// - defaultFgIndex: the color table index of the default foreground color.
|
||||
// - defaultBgIndex: the color table index of the default background color.
|
||||
// - reverseScreenMode: true if the screen mode is reversed.
|
||||
// - blinkingIsFaint: true if blinking should be interpreted as faint. (defaults to false)
|
||||
// - boldIsBright: true if "bold" should be interpreted as bright. (defaults to true)
|
||||
// Return Value:
|
||||
// - the foreground and background colors that should be displayed.
|
||||
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const std::array<COLORREF, 256>& colorTable,
|
||||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
std::pair<COLORREF, COLORREF> TextAttribute::CalculateRgbColors(const std::array<COLORREF, TextColor::TABLE_SIZE>& colorTable,
|
||||
const size_t defaultFgIndex,
|
||||
const size_t defaultBgIndex,
|
||||
const bool reverseScreenMode,
|
||||
const bool blinkingIsFaint,
|
||||
const bool boldIsBright) const noexcept
|
||||
{
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgColor, boldIsBright && IsBold());
|
||||
auto bg = _background.GetColor(colorTable, defaultBgColor);
|
||||
auto fg = _foreground.GetColor(colorTable, defaultFgIndex, boldIsBright && IsBold());
|
||||
auto bg = _background.GetColor(colorTable, defaultBgIndex);
|
||||
if (IsFaint() || (IsBlinking() && blinkingIsFaint))
|
||||
{
|
||||
fg = (fg >> 1) & 0x7F7F7F; // Divide foreground color components by two.
|
||||
|
|
|
@ -64,9 +64,9 @@ public:
|
|||
static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept;
|
||||
WORD GetLegacyAttributes() const noexcept;
|
||||
|
||||
std::pair<COLORREF, COLORREF> CalculateRgbColors(const std::array<COLORREF, 256>& colorTable,
|
||||
const COLORREF defaultFgColor,
|
||||
const COLORREF defaultBgColor,
|
||||
std::pair<COLORREF, COLORREF> CalculateRgbColors(const std::array<COLORREF, TextColor::TABLE_SIZE>& colorTable,
|
||||
const size_t defaultFgIndex,
|
||||
const size_t defaultBgIndex,
|
||||
const bool reverseScreenMode = false,
|
||||
const bool blinkingIsFaint = false,
|
||||
const bool boldIsBright = true) const noexcept;
|
||||
|
|
|
@ -139,14 +139,16 @@ void TextColor::SetDefault() noexcept
|
|||
// Arguments:
|
||||
// - colorTable: The table of colors we should use to look up the value of
|
||||
// an indexed attribute from.
|
||||
// - defaultColor: The color value to use if we're a default attribute.
|
||||
// - defaultIndex: The color table index to use if we're a default attribute.
|
||||
// - brighten: if true, we'll brighten a dark color table index.
|
||||
// Return Value:
|
||||
// - a COLORREF containing the real value of this TextColor.
|
||||
COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const COLORREF defaultColor, bool brighten) const noexcept
|
||||
COLORREF TextColor::GetColor(const std::array<COLORREF, TextColor::TABLE_SIZE>& colorTable, const size_t defaultIndex, bool brighten) const noexcept
|
||||
{
|
||||
if (IsDefault())
|
||||
{
|
||||
const auto defaultColor = til::at(colorTable, defaultIndex);
|
||||
|
||||
if (brighten)
|
||||
{
|
||||
// See MSFT:20266024 for context on this fix.
|
||||
|
|
|
@ -65,6 +65,11 @@ public:
|
|||
static constexpr BYTE BRIGHT_CYAN = 14;
|
||||
static constexpr BYTE BRIGHT_WHITE = 15;
|
||||
|
||||
static constexpr size_t DEFAULT_FOREGROUND = 256;
|
||||
static constexpr size_t DEFAULT_BACKGROUND = 257;
|
||||
static constexpr size_t CURSOR_COLOR = 258;
|
||||
static constexpr size_t TABLE_SIZE = 259;
|
||||
|
||||
constexpr TextColor() noexcept :
|
||||
_meta{ ColorType::IsDefault },
|
||||
_red{ 0 },
|
||||
|
@ -103,7 +108,7 @@ public:
|
|||
void SetIndex(const BYTE index, const bool isIndex256) noexcept;
|
||||
void SetDefault() noexcept;
|
||||
|
||||
COLORREF GetColor(const std::array<COLORREF, 256>& colorTable, const COLORREF defaultColor, bool brighten = false) const noexcept;
|
||||
COLORREF GetColor(const std::array<COLORREF, TABLE_SIZE>& colorTable, const size_t defaultIndex, bool brighten = false) const noexcept;
|
||||
BYTE GetLegacyIndex(const BYTE defaultIndex) const noexcept;
|
||||
|
||||
constexpr BYTE GetIndex() const noexcept
|
||||
|
|
|
@ -27,9 +27,7 @@ Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
|
|||
_fDeferCursorRedraw(false),
|
||||
_fHaveDeferredCursorRedraw(false),
|
||||
_ulSize(ulSize),
|
||||
_cursorType(CursorType::Legacy),
|
||||
_fUseColor(false),
|
||||
_color(s_InvertCursorColor)
|
||||
_cursorType(CursorType::Legacy)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -143,10 +141,9 @@ void Cursor::SetSize(const ULONG ulSize) noexcept
|
|||
_RedrawCursor();
|
||||
}
|
||||
|
||||
void Cursor::SetStyle(const ULONG ulSize, const COLORREF color, const CursorType type) noexcept
|
||||
void Cursor::SetStyle(const ULONG ulSize, const CursorType type) noexcept
|
||||
{
|
||||
_ulSize = ulSize;
|
||||
_color = color;
|
||||
_cursorType = type;
|
||||
|
||||
_RedrawCursor();
|
||||
|
@ -285,7 +282,6 @@ void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept
|
|||
// Size will be handled separately in the resize operation.
|
||||
//_ulSize = OtherCursor._ulSize;
|
||||
_cursorType = OtherCursor._cursorType;
|
||||
_color = OtherCursor._color;
|
||||
}
|
||||
|
||||
void Cursor::DelayEOLWrap(const COORD coordDelayedAt) noexcept
|
||||
|
@ -335,21 +331,6 @@ const CursorType Cursor::GetType() const noexcept
|
|||
return _cursorType;
|
||||
}
|
||||
|
||||
const bool Cursor::IsUsingColor() const noexcept
|
||||
{
|
||||
return GetColor() != INVALID_COLOR;
|
||||
}
|
||||
|
||||
const COLORREF Cursor::GetColor() const noexcept
|
||||
{
|
||||
return _color;
|
||||
}
|
||||
|
||||
void Cursor::SetColor(const unsigned int color) noexcept
|
||||
{
|
||||
_color = gsl::narrow_cast<COLORREF>(color);
|
||||
}
|
||||
|
||||
void Cursor::SetType(const CursorType type) noexcept
|
||||
{
|
||||
_cursorType = type;
|
||||
|
|
|
@ -24,7 +24,6 @@ class TextBuffer;
|
|||
class Cursor final
|
||||
{
|
||||
public:
|
||||
static const unsigned int s_InvertCursorColor = INVALID_COLOR;
|
||||
// the following values are used to create the textmode cursor.
|
||||
static constexpr unsigned int CURSOR_SMALL_SIZE = 25; // large enough to be one pixel on a six pixel font
|
||||
|
||||
|
@ -51,8 +50,6 @@ public:
|
|||
COORD GetPosition() const noexcept;
|
||||
|
||||
const CursorType GetType() const noexcept;
|
||||
const bool IsUsingColor() const noexcept;
|
||||
const COLORREF GetColor() const noexcept;
|
||||
|
||||
void StartDeferDrawing() noexcept;
|
||||
bool IsDeferDrawing() noexcept;
|
||||
|
@ -67,7 +64,7 @@ public:
|
|||
void SetIsPopupShown(const bool fIsPopupShown) noexcept;
|
||||
void SetDelay(const bool fDelay) noexcept;
|
||||
void SetSize(const ULONG ulSize) noexcept;
|
||||
void SetStyle(const ULONG ulSize, const COLORREF color, const CursorType type) noexcept;
|
||||
void SetStyle(const ULONG ulSize, const CursorType type) noexcept;
|
||||
|
||||
void SetPosition(const COORD cPosition) noexcept;
|
||||
void SetXPosition(const int NewX) noexcept;
|
||||
|
@ -84,7 +81,6 @@ public:
|
|||
COORD GetDelayedAtPosition() const noexcept;
|
||||
bool IsDelayedEOLWrap() const noexcept;
|
||||
|
||||
void SetColor(const unsigned int color) noexcept;
|
||||
void SetType(const CursorType type) noexcept;
|
||||
|
||||
private:
|
||||
|
@ -117,6 +113,4 @@ private:
|
|||
void _RedrawCursorAlways() noexcept;
|
||||
|
||||
CursorType _cursorType;
|
||||
bool _fUseColor;
|
||||
COLORREF _color;
|
||||
};
|
||||
|
|
|
@ -24,9 +24,11 @@ class TextAttributeTests
|
|||
TEST_METHOD(TestRoundtripDefaultColors);
|
||||
TEST_METHOD(TestBoldAsBright);
|
||||
|
||||
std::array<COLORREF, 256> _colorTable;
|
||||
COLORREF _defaultFg = RGB(1, 2, 3);
|
||||
COLORREF _defaultBg = RGB(4, 5, 6);
|
||||
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
|
||||
const COLORREF _defaultFg = RGB(1, 2, 3);
|
||||
const COLORREF _defaultBg = RGB(4, 5, 6);
|
||||
const size_t _defaultFgIndex = TextColor::DEFAULT_FOREGROUND;
|
||||
const size_t _defaultBgIndex = TextColor::DEFAULT_BACKGROUND;
|
||||
};
|
||||
|
||||
bool TextAttributeTests::ClassSetup()
|
||||
|
@ -47,6 +49,8 @@ bool TextAttributeTests::ClassSetup()
|
|||
_colorTable[13] = RGB(180, 0, 158); // Bright Magenta
|
||||
_colorTable[14] = RGB(249, 241, 165); // Bright Yellow
|
||||
_colorTable[15] = RGB(242, 242, 242); // White
|
||||
_colorTable[_defaultFgIndex] = _defaultFg;
|
||||
_colorTable[_defaultBgIndex] = _defaultBg;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -132,17 +136,17 @@ void TextAttributeTests::TestTextAttributeColorGetters()
|
|||
// values when reverse video is not set
|
||||
VERIFY_IS_FALSE(attr.IsReverseVideo());
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(red, green), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(red, green), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// with reverse video set, calculated foreground/background values should be
|
||||
// switched while getters stay the same
|
||||
attr.SetReverseVideo(true);
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, red), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, red), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// reset the reverse video
|
||||
attr.SetReverseVideo(false);
|
||||
|
@ -151,17 +155,17 @@ void TextAttributeTests::TestTextAttributeColorGetters()
|
|||
// while the background and getters stay the same
|
||||
attr.SetFaint(true);
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(faintRed, green), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(faintRed, green), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// with reverse video set, calculated foreground/background values should be
|
||||
// switched, and the background fainter, while getters stay the same
|
||||
attr.SetReverseVideo(true);
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, faintRed), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, faintRed), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// reset the reverse video and faint attributes
|
||||
attr.SetReverseVideo(false);
|
||||
|
@ -171,17 +175,17 @@ void TextAttributeTests::TestTextAttributeColorGetters()
|
|||
// background, while getters stay the same
|
||||
attr.SetInvisible(true);
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, green), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(green, green), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// with reverse video set, the calculated background value should match
|
||||
// the foreground, while getters stay the same
|
||||
attr.SetReverseVideo(true);
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(red, red), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(red, red), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
}
|
||||
|
||||
void TextAttributeTests::TestReverseDefaultColors()
|
||||
|
@ -194,34 +198,34 @@ void TextAttributeTests::TestReverseDefaultColors()
|
|||
// values when reverse video is not set
|
||||
VERIFY_IS_FALSE(attr.IsReverseVideo());
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
// with reverse video set, calculated foreground/background values should be
|
||||
// switched while getters stay the same
|
||||
attr.SetReverseVideo(true);
|
||||
VERIFY_IS_TRUE(attr.IsReverseVideo());
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultBg, _defaultFg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultBg, _defaultFg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
attr.SetForeground(red);
|
||||
VERIFY_IS_TRUE(attr.IsReverseVideo());
|
||||
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultBg, red), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(red, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultBg, red), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
|
||||
attr.Invert();
|
||||
VERIFY_IS_FALSE(attr.IsReverseVideo());
|
||||
attr.SetDefaultForeground();
|
||||
attr.SetBackground(green);
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, green), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(green, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, green), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex));
|
||||
}
|
||||
|
||||
void TextAttributeTests::TestRoundtripDefaultColors()
|
||||
|
@ -277,43 +281,43 @@ void TextAttributeTests::TestBoldAsBright()
|
|||
// values when not bold
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFg));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBg));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(_colorTable, _defaultFgIndex));
|
||||
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(_colorTable, _defaultBgIndex));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
|
||||
// with bold set, calculated foreground/background values shouldn't change for the default colors.
|
||||
attr.SetBold(true);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
|
||||
attr.SetIndexedForeground(TextColor::DARK_BLACK);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"Foreground should be bright black when bold is bright is enabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
|
||||
Log::Comment(L"Foreground should be dark black when bold is bright is disabled");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
|
||||
attr.SetIndexedBackground(TextColor::DARK_GREEN);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
Log::Comment(L"background should be unaffected by 'bold is bright'");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
|
||||
attr.SetBold(false);
|
||||
VERIFY_IS_FALSE(attr.IsBold());
|
||||
Log::Comment(L"when not bold, 'bold is bright' changes nothing");
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
|
||||
Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing");
|
||||
attr.SetBold(true);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, true));
|
||||
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFgIndex, _defaultBgIndex, false, false, false));
|
||||
}
|
||||
|
|
|
@ -23,9 +23,11 @@ class TextColorTests
|
|||
TEST_METHOD(TestRgbColor);
|
||||
TEST_METHOD(TestChangeColor);
|
||||
|
||||
std::array<COLORREF, 256> _colorTable;
|
||||
COLORREF _defaultFg = RGB(1, 2, 3);
|
||||
COLORREF _defaultBg = RGB(4, 5, 6);
|
||||
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
|
||||
const COLORREF _defaultFg = RGB(1, 2, 3);
|
||||
const COLORREF _defaultBg = RGB(4, 5, 6);
|
||||
const size_t _defaultFgIndex = TextColor::DEFAULT_FOREGROUND;
|
||||
const size_t _defaultBgIndex = TextColor::DEFAULT_BACKGROUND;
|
||||
};
|
||||
|
||||
bool TextColorTests::ClassSetup()
|
||||
|
@ -46,6 +48,8 @@ bool TextColorTests::ClassSetup()
|
|||
_colorTable[13] = RGB(180, 0, 158); // Bright Magenta
|
||||
_colorTable[14] = RGB(249, 241, 165); // Bright Yellow
|
||||
_colorTable[15] = RGB(242, 242, 242); // White
|
||||
_colorTable[_defaultFgIndex] = _defaultFg;
|
||||
_colorTable[_defaultBgIndex] = _defaultBg;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,16 +61,16 @@ void TextColorTests::TestDefaultColor()
|
|||
VERIFY_IS_FALSE(defaultColor.IsLegacy());
|
||||
VERIFY_IS_FALSE(defaultColor.IsRgb());
|
||||
|
||||
auto color = defaultColor.GetColor(_colorTable, _defaultFg, false);
|
||||
auto color = defaultColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_defaultFg, color);
|
||||
|
||||
color = defaultColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = defaultColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_defaultFg, color);
|
||||
|
||||
color = defaultColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = defaultColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_defaultBg, color);
|
||||
|
||||
color = defaultColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = defaultColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_defaultBg, color);
|
||||
}
|
||||
|
||||
|
@ -78,16 +82,16 @@ void TextColorTests::TestDarkIndexColor()
|
|||
VERIFY_IS_TRUE(indexColor.IsLegacy());
|
||||
VERIFY_IS_FALSE(indexColor.IsRgb());
|
||||
|
||||
auto color = indexColor.GetColor(_colorTable, _defaultFg, false);
|
||||
auto color = indexColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[7], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = indexColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = indexColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[7], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = indexColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
}
|
||||
|
||||
|
@ -99,16 +103,16 @@ void TextColorTests::TestBrightIndexColor()
|
|||
VERIFY_IS_TRUE(indexColor.IsLegacy());
|
||||
VERIFY_IS_FALSE(indexColor.IsRgb());
|
||||
|
||||
auto color = indexColor.GetColor(_colorTable, _defaultFg, false);
|
||||
auto color = indexColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = indexColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = indexColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = indexColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = indexColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
}
|
||||
|
||||
|
@ -121,16 +125,16 @@ void TextColorTests::TestRgbColor()
|
|||
VERIFY_IS_FALSE(rgbColor.IsLegacy());
|
||||
VERIFY_IS_TRUE(rgbColor.IsRgb());
|
||||
|
||||
auto color = rgbColor.GetColor(_colorTable, _defaultFg, false);
|
||||
auto color = rgbColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
}
|
||||
|
||||
|
@ -143,55 +147,55 @@ void TextColorTests::TestChangeColor()
|
|||
VERIFY_IS_FALSE(rgbColor.IsLegacy());
|
||||
VERIFY_IS_TRUE(rgbColor.IsRgb());
|
||||
|
||||
auto color = rgbColor.GetColor(_colorTable, _defaultFg, false);
|
||||
auto color = rgbColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(myColor, color);
|
||||
|
||||
rgbColor.SetDefault();
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_defaultFg, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_defaultFg, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_defaultBg, color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_defaultBg, color);
|
||||
|
||||
rgbColor.SetIndex(7, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[7], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[7], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
rgbColor.SetIndex(15, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultFgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, false);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, false);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBg, true);
|
||||
color = rgbColor.GetColor(_colorTable, _defaultBgIndex, true);
|
||||
VERIFY_ARE_EQUAL(_colorTable[15], color);
|
||||
}
|
||||
|
|
|
@ -61,13 +61,26 @@
|
|||
|
||||
<Import Project="$(MSBuildThisFileDirectory)..\CascadiaResources.build.items" />
|
||||
<Import Project="$(OpenConsoleDir)src\wap-common.build.post.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WindowsTerminal\WindowsTerminal.vcxproj" />
|
||||
<ProjectReference Include="..\..\host\exe\Host.EXE.vcxproj" />
|
||||
<ProjectReference Include="..\..\host\proxy\Host.Proxy.vcxproj" />
|
||||
<ProjectReference Include="..\TerminalAzBridge\TerminalAzBridge.vcxproj" />
|
||||
<ProjectReference Include="..\ShellExtension\WindowsTerminalShellExt.vcxproj" />
|
||||
<ProjectReference Include="..\wt\wt.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj">
|
||||
<Project>{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalAzBridge\TerminalAzBridge.vcxproj">
|
||||
<Project>{067F0A06-FCB7-472C-96E9-B03B54E8E18D}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj">
|
||||
<Project>{f2ed628a-db22-446f-a081-4cc845b51a2b}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\wt\wt.vcxproj">
|
||||
<Project>{506fd703-baa7-4f6e-9361-64f550ec8fca}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\host\exe\Host.EXE.vcxproj">
|
||||
<Project>{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\host\proxy\Host.Proxy.vcxproj">
|
||||
<Project>{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="OpenConsoleStompSourceProjectForWapProject" BeforeTargets="_ConvertItems">
|
||||
|
|
|
@ -239,8 +239,8 @@ HRESULT HwndTerminal::Initialize()
|
|||
_terminal->SetBackgroundCallback([](auto) {});
|
||||
|
||||
_terminal->Create(COORD{ 80, 25 }, 1000, *_renderer);
|
||||
_terminal->SetDefaultBackground(RGB(12, 12, 12));
|
||||
_terminal->SetDefaultForeground(RGB(204, 204, 204));
|
||||
_terminal->SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, RGB(12, 12, 12));
|
||||
_terminal->SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, RGB(204, 204, 204));
|
||||
_terminal->SetWriteInputCallback([=](std::wstring& input) noexcept { _WriteTextToConnection(input); });
|
||||
localPointerToThread->EnablePainting();
|
||||
|
||||
|
@ -781,8 +781,8 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
|
|||
{
|
||||
auto lock = publicTerminal->_terminal->LockForWriting();
|
||||
|
||||
publicTerminal->_terminal->SetDefaultForeground(theme.DefaultForeground);
|
||||
publicTerminal->_terminal->SetDefaultBackground(theme.DefaultBackground);
|
||||
publicTerminal->_terminal->SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, theme.DefaultForeground);
|
||||
publicTerminal->_terminal->SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, theme.DefaultBackground);
|
||||
publicTerminal->_renderEngine->SetSelectionBackground(theme.DefaultSelectionBackground, theme.SelectionBackgroundAlpha);
|
||||
|
||||
// Set the font colors
|
||||
|
|
|
@ -318,7 +318,29 @@
|
|||
</ProjectReference>
|
||||
<!-- For whatever reason, we can't include the TerminalControl and
|
||||
TerminalSettings projects' winmds via project references. So we'll have to
|
||||
manually include the winmds as References below -->
|
||||
manually include the winmds as References below
|
||||
|
||||
BODGY: we do need to add a ProjectReference to TerminalControl.vcxproj,
|
||||
with Private=true, ReferenceOutputAssembly=false, so that Visual Studio's
|
||||
"Fast Up-to-date Check" will work with this project. If we don't, the Fast
|
||||
Up-to-date Check will look for the .xaml files from that project in our
|
||||
output, which won't actually be there.
|
||||
|
||||
We do still need to separately reference the winmds manually below, which is annoying.
|
||||
-->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\dll\TerminalControl.vcxproj">
|
||||
<!-- Private:true and ReferenceOutputAssembly:false, in combination with
|
||||
the manual reference to TerminalControl.winmd below make sure that this
|
||||
project will compile correct, and that we won't roll up the TermControl
|
||||
xbf's into the packaging project twice. -->
|
||||
<Private>true</Private>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj">
|
||||
<Private>true</Private>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- This is a hack to get the ARM64 CI build working. See
|
||||
|
|
|
@ -3,38 +3,38 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "TerminalPage.h"
|
||||
#include "Utils.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "TerminalPage.g.cpp"
|
||||
#include "RenameWindowRequestedArgs.g.cpp"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <inc/WindowingBehavior.h>
|
||||
#include <LibraryResources.h>
|
||||
#include <TerminalCore/ControlKeyStates.hpp>
|
||||
#include <til/latch.h>
|
||||
|
||||
#include "TerminalPage.g.cpp"
|
||||
#include <winrt/Windows.Storage.h>
|
||||
|
||||
#include "TabRowControl.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
#include "RenameWindowRequestedArgs.g.cpp"
|
||||
#include "../inc/WindowingBehavior.h"
|
||||
|
||||
#include <til/latch.h>
|
||||
#include "TabRowControl.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Control;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace ::TerminalApp;
|
||||
using namespace ::Microsoft::Console;
|
||||
using namespace ::Microsoft::Terminal::Core;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define HOOKUP_ACTION(action) _actionDispatch->action({ this, &TerminalPage::_Handle##action });
|
||||
|
@ -1038,29 +1038,153 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// Called when the users pressed keyBindings while CommandPalette is open.
|
||||
// - Called when the users pressed keyBindings while CommandPalette is open.
|
||||
// - This method is effectively an extract of TermControl::_KeyHandler and TermControl::_TryHandleKeyBinding.
|
||||
// Arguments:
|
||||
// - e: the KeyRoutedEventArgs containing info about the keystroke.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_KeyDownHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
const auto key = e.OriginalKey();
|
||||
const auto scanCode = e.KeyStatus().ScanCode;
|
||||
const auto coreWindow = CoreWindow::GetForCurrentThread();
|
||||
const auto ctrlDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
const auto altDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
||||
const auto shiftDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
||||
const auto keyStatus = e.KeyStatus();
|
||||
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
const auto modifiers = _GetPressedModifierKeys();
|
||||
|
||||
winrt::Microsoft::Terminal::Control::KeyChord kc{ ctrlDown, altDown, shiftDown, false, static_cast<int32_t>(key), static_cast<int32_t>(scanCode) };
|
||||
if (const auto cmd{ _settings.ActionMap().GetActionByKeyChord(kc) })
|
||||
// GH#11076:
|
||||
// For some weird reason we sometimes receive a WM_KEYDOWN
|
||||
// message without vkey or scanCode if a user drags a tab.
|
||||
// The KeyChord constructor has a debug assertion ensuring that all KeyChord
|
||||
// either have a valid vkey/scanCode. This is important, because this prevents
|
||||
// accidential insertion of invalid KeyChords into classes like ActionMap.
|
||||
if (!vkey && !scanCode)
|
||||
{
|
||||
if (CommandPalette().Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
|
||||
return;
|
||||
}
|
||||
|
||||
// Alt-Numpad# input will send us a character once the user releases
|
||||
// Alt, so we should be ignoring the individual keydowns. The character
|
||||
// will be sent through the TSFInputControl. See GH#1401 for more
|
||||
// details
|
||||
if (modifiers.IsAltPressed() && (vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GH#2235: Terminal::Settings hasn't been modified to differentiate
|
||||
// between AltGr and Ctrl+Alt yet.
|
||||
// -> Don't check for key bindings if this is an AltGr key combination.
|
||||
if (modifiers.IsAltGrPressed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto actionMap = _settings.ActionMap();
|
||||
if (!actionMap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cmd = actionMap.GetActionByKeyChord({
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
modifiers.IsWinPressed(),
|
||||
vkey,
|
||||
scanCode,
|
||||
});
|
||||
if (!cmd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_actionDispatch->DoAction(cmd.ActionAndArgs()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto p = CommandPalette(); p.Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
|
||||
{
|
||||
p.Visibility(Visibility::Collapsed);
|
||||
}
|
||||
|
||||
// Let's assume the user has bound the dead key "^" to a sendInput command that sends "b".
|
||||
// If the user presses the two keys "^a" it'll produce "bâ", despite us marking the key event as handled.
|
||||
// The following is used to manually "consume" such dead keys and clear them from the keyboard state.
|
||||
_ClearKeyboardState(vkey, scanCode);
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the modifier keys that are currently pressed. This can be used to
|
||||
// find out which modifiers (ctrl, alt, shift) are pressed in events that
|
||||
// don't necessarily include that state.
|
||||
// - This is a copy of TermControl::_GetPressedModifierKeys.
|
||||
// Return Value:
|
||||
// - The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
ControlKeyStates TerminalPage::_GetPressedModifierKeys() noexcept
|
||||
{
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
// DONT USE
|
||||
// != CoreVirtualKeyStates::None
|
||||
// OR
|
||||
// == CoreVirtualKeyStates::Down
|
||||
// Sometimes with the key down, the state is Down | Locked.
|
||||
// Sometimes with the key up, the state is Locked.
|
||||
// IsFlagSet(Down) is the only correct solution.
|
||||
|
||||
struct KeyModifier
|
||||
{
|
||||
VirtualKey vkey;
|
||||
ControlKeyStates flags;
|
||||
};
|
||||
|
||||
constexpr std::array<KeyModifier, 7> modifiers{ {
|
||||
{ VirtualKey::RightMenu, ControlKeyStates::RightAltPressed },
|
||||
{ VirtualKey::LeftMenu, ControlKeyStates::LeftAltPressed },
|
||||
{ VirtualKey::RightControl, ControlKeyStates::RightCtrlPressed },
|
||||
{ VirtualKey::LeftControl, ControlKeyStates::LeftCtrlPressed },
|
||||
{ VirtualKey::Shift, ControlKeyStates::ShiftPressed },
|
||||
{ VirtualKey::RightWindows, ControlKeyStates::RightWinPressed },
|
||||
{ VirtualKey::LeftWindows, ControlKeyStates::LeftWinPressed },
|
||||
} };
|
||||
|
||||
ControlKeyStates flags;
|
||||
|
||||
for (const auto& mod : modifiers)
|
||||
{
|
||||
const auto state = window.GetKeyState(mod.vkey);
|
||||
const auto isDown = WI_IsFlagSet(state, CoreVirtualKeyStates::Down);
|
||||
|
||||
if (isDown)
|
||||
{
|
||||
CommandPalette().Visibility(Visibility::Collapsed);
|
||||
flags |= mod.flags;
|
||||
}
|
||||
_actionDispatch->DoAction(cmd.ActionAndArgs());
|
||||
e.Handled(true);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Discards currently pressed dead keys.
|
||||
// - This is a copy of TermControl::_ClearKeyboardState.
|
||||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - scanCode: The scan code of the key pressed.
|
||||
void TerminalPage::_ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept
|
||||
{
|
||||
std::array<BYTE, 256> keyState;
|
||||
if (!GetKeyboardState(keyState.data()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// As described in "Sometimes you *want* to interfere with the keyboard's state buffer":
|
||||
// http://archives.miloush.net/michkap/archive/2006/09/10/748775.html
|
||||
// > "The key here is to keep trying to pass stuff to ToUnicode until -1 is not returned."
|
||||
std::array<wchar_t, 16> buffer;
|
||||
while (ToUnicodeEx(vkey, scanCode, keyState.data(), buffer.data(), gsl::narrow_cast<int>(buffer.size()), 0b1, nullptr) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,17 @@
|
|||
|
||||
static constexpr uint32_t DefaultRowsToScroll{ 3 };
|
||||
static constexpr std::wstring_view TabletInputServiceKey{ L"TabletInputService" };
|
||||
// fwdecl unittest classes
|
||||
|
||||
namespace TerminalAppLocalTests
|
||||
{
|
||||
class TabTests;
|
||||
class SettingsTests;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Microsoft::Terminal::Core
|
||||
{
|
||||
class ControlKeyStates;
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
|
@ -225,6 +230,8 @@ namespace winrt::TerminalApp::implementation
|
|||
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
static ::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() noexcept;
|
||||
static void _ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept;
|
||||
void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap) noexcept;
|
||||
void _RegisterActionCallbacks();
|
||||
|
||||
|
|
|
@ -68,5 +68,22 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!--
|
||||
BODGY
|
||||
|
||||
The wapproj `GetResolvedWinMD` target tries to get a winmd from every cppwinrt
|
||||
executable we put in the package. But we DON'T produce a winmd. This makes the
|
||||
FastUpToDate check fail every time, and leads to the whole wapproj build
|
||||
running even if you're just f5'ing the package. EVEN AFTER A SUCCESSFUL BUILD.
|
||||
|
||||
Setting GenerateWindowsMetadata=false is enough to tell the build system that
|
||||
we don't produce one, and get it off our backs.
|
||||
-->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -97,4 +97,39 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
</Project>
|
||||
|
||||
<!--
|
||||
BODGY:
|
||||
|
||||
We depend on `cpprest142*.dll`, which comes from our vcpkg dependency. As a
|
||||
part of the vcpkg dependency restore, msbuild will call the `deployBinary()`
|
||||
function in
|
||||
`packages\vcpkg-cpprestsdk.2.10.14\scripts\BuildSystems\msbuild\AppLocal.ps1`.
|
||||
That function does the actual job of copying the file. It copies it outside of
|
||||
MsBuild. MsBuild then, in the `_CopyFilesMarkedCopyLocal` target, determines
|
||||
that it needs to copy `cpprest142*.dll`, because that dll is a member of
|
||||
`@(ReferencesCopiedInThisBuild)`. However, the file's already been copied, so
|
||||
MsBuild never copies it. But that also prevents MsBuild from setting
|
||||
`WroteAtLeastOneFile`, which then means that MsBuild will never create the
|
||||
.CopyComplete file for this project.
|
||||
|
||||
Because that file is missing, MsBuild will never think the project is up to
|
||||
date, and the FastUpToDate check in VS will always force MsBuild to run a pass
|
||||
on this project.
|
||||
|
||||
To mitigate this, we're adding this other target here, which runs after
|
||||
_CopyFilesMarkedCopyLocal, and always creates the CopyUpToDateMarker. This
|
||||
makes the FastUpToDate check succeed.
|
||||
-->
|
||||
|
||||
<Target
|
||||
Name="_Post_CopyFilesMarkedCopyLocal"
|
||||
AfterTargets="_CopyFilesMarkedCopyLocal"
|
||||
Condition="'@(ReferenceCopyLocalPaths)' != ''">
|
||||
|
||||
<Touch Files="@(CopyUpToDateMarker)"
|
||||
AlwaysCreate="true" />
|
||||
</Target>
|
||||
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1089,7 +1089,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
til::color ControlCore::BackgroundColor() const
|
||||
{
|
||||
return _terminal->GetDefaultBackground();
|
||||
return _terminal->GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -773,12 +773,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_HidePointerCursorHandlers(*this, nullptr);
|
||||
|
||||
const auto ch = e.Character();
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(e.KeyStatus().ScanCode);
|
||||
const auto keyStatus = e.KeyStatus();
|
||||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
auto modifiers = _GetPressedModifierKeys();
|
||||
if (e.KeyStatus().IsExtendedKey)
|
||||
|
||||
if (keyStatus.IsExtendedKey)
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
|
||||
const bool handled = _core.SendCharEvent(ch, scanCode, modifiers);
|
||||
e.Handled(handled);
|
||||
}
|
||||
|
@ -873,6 +876,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
|
||||
auto modifiers = _GetPressedModifierKeys();
|
||||
|
||||
if (keyStatus.IsExtendedKey)
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
|
||||
// GH#11076:
|
||||
// For some weird reason we sometimes receive a WM_KEYDOWN
|
||||
// message without vkey or scanCode if a user drags a tab.
|
||||
|
@ -906,11 +914,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return;
|
||||
}
|
||||
|
||||
if (keyStatus.IsExtendedKey)
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
|
||||
// Alt-Numpad# input will send us a character once the user releases
|
||||
// Alt, so we should be ignoring the individual keydowns. The character
|
||||
// will be sent through the TSFInputControl. See GH#1401 for more
|
||||
|
@ -988,7 +991,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - scanCode: The scan code of the key pressed.
|
||||
void TermControl::_ClearKeyboardState(const WORD vkey, const WORD scanCode) const noexcept
|
||||
void TermControl::_ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept
|
||||
{
|
||||
std::array<BYTE, 256> keyState;
|
||||
if (!GetKeyboardState(keyState.data()))
|
||||
|
@ -2060,7 +2063,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// don't necessarily include that state.
|
||||
// Return Value:
|
||||
// - The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
ControlKeyStates TermControl::_GetPressedModifierKeys() const
|
||||
ControlKeyStates TermControl::_GetPressedModifierKeys() noexcept
|
||||
{
|
||||
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
||||
// DONT USE
|
||||
|
|
|
@ -245,9 +245,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
void _UpdateAutoScroll(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
|
||||
|
||||
void _KeyHandler(Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e, const bool keyDown);
|
||||
::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() const;
|
||||
static ::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() noexcept;
|
||||
bool _TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const;
|
||||
void _ClearKeyboardState(const WORD vkey, const WORD scanCode) const noexcept;
|
||||
static void _ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept;
|
||||
bool _TrySendKeyEvent(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
|
||||
|
||||
const til::point _toTerminalOrigin(winrt::Windows::Foundation::Point cursorPosition);
|
||||
|
|
|
@ -40,13 +40,10 @@ namespace Microsoft::Terminal::Core
|
|||
virtual bool WarningBell() noexcept = 0;
|
||||
virtual bool SetWindowTitle(std::wstring_view title) noexcept = 0;
|
||||
|
||||
virtual bool SetColorTableEntry(const size_t tableIndex, const DWORD color) noexcept = 0;
|
||||
virtual COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept = 0;
|
||||
virtual bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept = 0;
|
||||
|
||||
virtual bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept = 0;
|
||||
virtual bool SetCursorColor(const DWORD color) noexcept = 0;
|
||||
|
||||
virtual bool SetDefaultForeground(const DWORD color) noexcept = 0;
|
||||
virtual bool SetDefaultBackground(const DWORD color) noexcept = 0;
|
||||
|
||||
virtual bool SetInputMode(const ::Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) noexcept = 0;
|
||||
|
||||
|
|
|
@ -41,8 +41,6 @@ Terminal::Terminal() :
|
|||
_mutableViewport{ Viewport::Empty() },
|
||||
_title{},
|
||||
_colorTable{},
|
||||
_defaultFg{ RGB(255, 255, 255) },
|
||||
_defaultBg{ ARGB(0, 0, 0, 0) },
|
||||
_screenReversed{ false },
|
||||
_pfnWriteInput{ nullptr },
|
||||
_scrollOffset{ 0 },
|
||||
|
@ -81,6 +79,10 @@ Terminal::Terminal() :
|
|||
_terminalInput = std::make_unique<TerminalInput>(passAlongInput);
|
||||
|
||||
_InitializeColorTable();
|
||||
|
||||
_colorTable.at(TextColor::DEFAULT_FOREGROUND) = RGB(255, 255, 255);
|
||||
_colorTable.at(TextColor::DEFAULT_BACKGROUND) = ARGB(0, 0, 0, 0);
|
||||
_colorTable.at(TextColor::CURSOR_COLOR) = INVALID_COLOR;
|
||||
}
|
||||
|
||||
void Terminal::Create(COORD viewportSize, SHORT scrollbackLines, IRenderTarget& renderTarget)
|
||||
|
@ -180,9 +182,13 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
|||
{
|
||||
// Set the default background as transparent to prevent the
|
||||
// DX layer from overwriting the background image or acrylic effect
|
||||
til::color newBackgroundColor{ appearance.DefaultBackground() };
|
||||
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||
_defaultFg = appearance.DefaultForeground();
|
||||
const til::color newBackgroundColor{ appearance.DefaultBackground() };
|
||||
_colorTable.at(TextColor::DEFAULT_BACKGROUND) = newBackgroundColor.with_alpha(0);
|
||||
const til::color newForegroundColor{ appearance.DefaultForeground() };
|
||||
_colorTable.at(TextColor::DEFAULT_FOREGROUND) = newForegroundColor;
|
||||
const til::color newCursorColor{ appearance.CursorColor() };
|
||||
_colorTable.at(TextColor::CURSOR_COLOR) = newCursorColor;
|
||||
|
||||
_intenseIsBright = appearance.IntenseIsBright();
|
||||
_adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
|
||||
|
||||
|
@ -221,9 +227,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
|||
|
||||
if (_buffer)
|
||||
{
|
||||
_buffer->GetCursor().SetStyle(appearance.CursorHeight(),
|
||||
til::color{ appearance.CursorColor() },
|
||||
cursorShape);
|
||||
_buffer->GetCursor().SetStyle(appearance.CursorHeight(), cursorShape);
|
||||
}
|
||||
|
||||
_defaultCursorShape = cursorShape;
|
||||
|
|
|
@ -106,11 +106,9 @@ public:
|
|||
bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) noexcept override;
|
||||
bool WarningBell() noexcept override;
|
||||
bool SetWindowTitle(std::wstring_view title) noexcept override;
|
||||
COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept override;
|
||||
bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept override;
|
||||
bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept override;
|
||||
bool SetCursorColor(const COLORREF color) noexcept override;
|
||||
bool SetDefaultForeground(const COLORREF color) noexcept override;
|
||||
bool SetDefaultBackground(const COLORREF color) noexcept override;
|
||||
|
||||
bool SetInputMode(const ::Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) noexcept override;
|
||||
|
||||
|
@ -212,7 +210,6 @@ public:
|
|||
void ClearPatternTree() noexcept;
|
||||
|
||||
const std::optional<til::color> GetTabColor() const noexcept;
|
||||
til::color GetDefaultBackground() const noexcept;
|
||||
|
||||
Microsoft::Console::Render::BlinkingState& GetBlinkingState() const noexcept;
|
||||
|
||||
|
@ -281,9 +278,7 @@ private:
|
|||
std::optional<til::color> _startingTabColor;
|
||||
|
||||
// This is still stored as a COLORREF because it interacts with some code in ConTypes
|
||||
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
|
||||
til::color _defaultFg;
|
||||
til::color _defaultBg;
|
||||
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
|
||||
CursorType _defaultCursorShape;
|
||||
bool _screenReversed;
|
||||
mutable Microsoft::Console::Render::BlinkingState _blinkingState;
|
||||
|
|
|
@ -69,14 +69,6 @@ COORD Terminal::GetCursorPosition() noexcept
|
|||
return newPos;
|
||||
}
|
||||
|
||||
bool Terminal::SetCursorColor(const COLORREF color) noexcept
|
||||
try
|
||||
{
|
||||
_buffer->GetCursor().SetColor(color);
|
||||
return true;
|
||||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Moves the cursor down one line, and possibly also to the leftmost column.
|
||||
// Arguments:
|
||||
|
@ -370,6 +362,22 @@ try
|
|||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves the value in the colortable at the specified index.
|
||||
// Arguments:
|
||||
// - tableIndex: the index of the color table to retrieve.
|
||||
// Return Value:
|
||||
// - the COLORREF value for the color at that index in the table.
|
||||
COLORREF Terminal::GetColorTableEntry(const size_t tableIndex) const noexcept
|
||||
try
|
||||
{
|
||||
return _colorTable.at(tableIndex);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return INVALID_COLOR;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates the value in the colortable at index tableIndex to the new color
|
||||
// color. color is a COLORREF, format 0x00BBGGRR.
|
||||
|
@ -383,6 +391,11 @@ try
|
|||
{
|
||||
_colorTable.at(tableIndex) = color;
|
||||
|
||||
if (tableIndex == TextColor::DEFAULT_BACKGROUND)
|
||||
{
|
||||
_pfnBackgroundColorChanged(color);
|
||||
}
|
||||
|
||||
// Repaint everything - the colors might have changed
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
|
@ -442,46 +455,6 @@ bool Terminal::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) noex
|
|||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates the default foreground color from a COLORREF, format 0x00BBGGRR.
|
||||
// Arguments:
|
||||
// - color: the new COLORREF to use as the default foreground color
|
||||
// Return Value:
|
||||
// - true
|
||||
bool Terminal::SetDefaultForeground(const COLORREF color) noexcept
|
||||
try
|
||||
{
|
||||
_defaultFg = color;
|
||||
|
||||
// Repaint everything - the colors might have changed
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Method Description:
|
||||
// - Updates the default background color from a COLORREF, format 0x00BBGGRR.
|
||||
// Arguments:
|
||||
// - color: the new COLORREF to use as the default background color
|
||||
// Return Value:
|
||||
// - true
|
||||
bool Terminal::SetDefaultBackground(const COLORREF color) noexcept
|
||||
try
|
||||
{
|
||||
_defaultBg = color;
|
||||
_pfnBackgroundColorChanged(color);
|
||||
|
||||
// Repaint everything - the colors might have changed
|
||||
_buffer->GetRenderTarget().TriggerRedrawAll();
|
||||
return true;
|
||||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
til::color Terminal::GetDefaultBackground() const noexcept
|
||||
{
|
||||
return _defaultBg;
|
||||
}
|
||||
|
||||
bool Terminal::SetInputMode(const TerminalInput::Mode mode, const bool enabled) noexcept
|
||||
try
|
||||
{
|
||||
|
|
|
@ -227,7 +227,7 @@ CATCH_LOG_RETURN_FALSE()
|
|||
bool TerminalDispatch::SetCursorColor(const DWORD color) noexcept
|
||||
try
|
||||
{
|
||||
return _terminalApi.SetCursorColor(color);
|
||||
return _terminalApi.SetColorTableEntry(TextColor::CURSOR_COLOR, color);
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
|
||||
|
@ -247,7 +247,7 @@ CATCH_LOG_RETURN_FALSE()
|
|||
bool TerminalDispatch::SetDefaultForeground(const DWORD color) noexcept
|
||||
try
|
||||
{
|
||||
return _terminalApi.SetDefaultForeground(color);
|
||||
return _terminalApi.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, color);
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
|
||||
|
@ -260,7 +260,7 @@ CATCH_LOG_RETURN_FALSE()
|
|||
bool TerminalDispatch::SetDefaultBackground(const DWORD color) noexcept
|
||||
try
|
||||
{
|
||||
return _terminalApi.SetDefaultBackground(color);
|
||||
return _terminalApi.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, color);
|
||||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
|
||||
|
|
|
@ -73,19 +73,19 @@ std::pair<COLORREF, COLORREF> Terminal::GetAttributeColors(const TextAttribute&
|
|||
if (attr.IsReverseVideo() ^ _screenReversed)
|
||||
{
|
||||
colors.first = _adjustedForegroundColors[fgIndex][bgIndex];
|
||||
colors.second = fgTextColor.GetColor(_colorTable, _defaultFg);
|
||||
colors.second = fgTextColor.GetColor(_colorTable, TextColor::DEFAULT_FOREGROUND);
|
||||
}
|
||||
else
|
||||
{
|
||||
colors.first = _adjustedForegroundColors[bgIndex][fgIndex];
|
||||
colors.second = bgTextColor.GetColor(_colorTable, _defaultBg);
|
||||
colors.second = bgTextColor.GetColor(_colorTable, TextColor::DEFAULT_BACKGROUND);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
colors = attr.CalculateRgbColors(_colorTable,
|
||||
_defaultFg,
|
||||
_defaultBg,
|
||||
TextColor::DEFAULT_FOREGROUND,
|
||||
TextColor::DEFAULT_BACKGROUND,
|
||||
_screenReversed,
|
||||
_blinkingState.IsBlinkingFaint(),
|
||||
_intenseIsBright);
|
||||
|
@ -135,7 +135,7 @@ CursorType Terminal::GetCursorStyle() const noexcept
|
|||
|
||||
COLORREF Terminal::GetCursorColor() const noexcept
|
||||
{
|
||||
return _buffer->GetCursor().GetColor();
|
||||
return _colorTable.at(TextColor::CURSOR_COLOR);
|
||||
}
|
||||
|
||||
bool Terminal::IsCursorDoubleWidth() const
|
||||
|
@ -312,8 +312,8 @@ void Terminal::_MakeAdjustedColorArray()
|
|||
// to include the default background and default foreground colors
|
||||
std::array<COLORREF, 18> colorTableWithDefaults;
|
||||
std::copy_n(std::begin(_colorTable), 16, std::begin(colorTableWithDefaults));
|
||||
colorTableWithDefaults[DefaultBgIndex] = _defaultBg;
|
||||
colorTableWithDefaults[DefaultFgIndex] = _defaultFg;
|
||||
colorTableWithDefaults[DefaultBgIndex] = _colorTable.at(TextColor::DEFAULT_BACKGROUND);
|
||||
colorTableWithDefaults[DefaultFgIndex] = _colorTable.at(TextColor::DEFAULT_FOREGROUND);
|
||||
for (auto fgIndex = 0; fgIndex < 18; ++fgIndex)
|
||||
{
|
||||
const auto fg = til::at(colorTableWithDefaults, fgIndex);
|
||||
|
|
|
@ -171,7 +171,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
THROW_IF_FAILED(fontFamily->GetFamilyNames(localizedFamilyNames.put()));
|
||||
|
||||
// construct a font entry for tracking
|
||||
if (auto fontEntry{ _GetFont(localizedFamilyNames) })
|
||||
if (const auto fontEntry{ _GetFont(localizedFamilyNames) })
|
||||
{
|
||||
// check if the font is monospaced
|
||||
try
|
||||
|
|
|
@ -197,9 +197,29 @@
|
|||
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
|
||||
<!-- For whatever reason, we can't include the TerminalControl and
|
||||
TerminalSettings projects' winmds via project references. So we'll have to
|
||||
manually include the winmds as References below -->
|
||||
manually include the winmds as References below
|
||||
|
||||
BODGY: we do need to add a ProjectReference to TerminalControl.vcxproj,
|
||||
with Private=true, ReferenceOutputAssembly=false, so that Visual Studio's
|
||||
"Fast Up-to-date Check" will work with this project. If we don't, the Fast
|
||||
Up-to-date Check will look for the .xaml files from that project in our
|
||||
output, which won't actually be there.
|
||||
|
||||
We do still need to separately reference the winmds manually below, which is annoying.
|
||||
-->
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\dll\TerminalControl.vcxproj">
|
||||
<!-- Private:true and ReferenceOutputAssembly:false, in combination with
|
||||
the manual reference to TerminalControl.winmd below make sure that this
|
||||
project will compile correct, and that we won't roll up the TermControl
|
||||
xbf's into the packaging project twice. -->
|
||||
<Private>true</Private>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
|
@ -266,4 +286,5 @@
|
|||
</Target>
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
<Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
</ProjectReference>
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\dll\TerminalControl.vcxproj">
|
||||
<!-- Private:false and ReferenceOutputAssembly:false, in combination with
|
||||
<!-- Private:true and ReferenceOutputAssembly:false, in combination with
|
||||
the manual reference to TerminalControl.winmd below make sure that this
|
||||
project will compile correct, and that we won't roll up the TermControl
|
||||
xbf's into the packaging project twice. -->
|
||||
|
|
|
@ -96,9 +96,10 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final
|
|||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetDefaultForegroundColor(INVALID_COLOR);
|
||||
gci.SetDefaultBackgroundColor(INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
|
||||
gci.SetFillAttribute(0x07); // DARK_WHITE on DARK_BLACK
|
||||
gci.CalculateDefaultColorIndices();
|
||||
|
||||
m_state->PrepareNewTextBufferInfo(true, TerminalViewWidth, TerminalViewHeight);
|
||||
auto& currentBuffer = gci.GetActiveOutputBuffer();
|
||||
|
|
|
@ -59,7 +59,6 @@ void TerminalApiTest::SetColorTableEntry()
|
|||
VERIFY_IS_TRUE(term.SetColorTableEntry(128, 100));
|
||||
VERIFY_IS_TRUE(term.SetColorTableEntry(255, 100));
|
||||
|
||||
VERIFY_IS_FALSE(term.SetColorTableEntry(256, 100));
|
||||
VERIFY_IS_FALSE(term.SetColorTableEntry(512, 100));
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,23 @@
|
|||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
BODGY
|
||||
|
||||
The wapproj `GetResolvedWinMD` target tries to get a winmd from every cppwinrt
|
||||
executable we put in the package. But we DON'T produce a winmd. This makes the
|
||||
FastUpToDate check fail every time, and leads to the whole wapproj build
|
||||
running even if you're just f5'ing the package. EVEN AFTER A SUCCESSFUL BUILD.
|
||||
|
||||
Setting GenerateWindowsMetadata=false is enough to tell the build system that
|
||||
we don't produce one, and get it off our backs.
|
||||
-->
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
|
|
|
@ -219,36 +219,6 @@ InputBuffer* const CONSOLE_INFORMATION::GetActiveInputBuffer() const
|
|||
return pInputBuffer;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Return the default foreground color of the console. If the settings are
|
||||
// configured to have a default foreground color (separate from the color
|
||||
// table), this will return that value. Otherwise it will return the value
|
||||
// from the colortable corresponding to our default attributes.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the default foreground color of the console.
|
||||
COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
|
||||
{
|
||||
const auto fg = GetDefaultForegroundColor();
|
||||
return fg != INVALID_COLOR ? fg : GetLegacyColorTableEntry(LOBYTE(GetFillAttribute()) & FG_ATTRS);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Return the default background color of the console. If the settings are
|
||||
// configured to have a default background color (separate from the color
|
||||
// table), this will return that value. Otherwise it will return the value
|
||||
// from the colortable corresponding to our default attributes.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the default background color of the console.
|
||||
COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept
|
||||
{
|
||||
const auto bg = GetDefaultBackgroundColor();
|
||||
return bg != INVALID_COLOR ? bg : GetLegacyColorTableEntry((LOBYTE(GetFillAttribute()) & BG_ATTRS) >> 4);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the colors of a particular text attribute, using our color table,
|
||||
// and our configured default attributes.
|
||||
|
@ -257,26 +227,12 @@ COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept
|
|||
// Return Value:
|
||||
// - The color values of the attribute's foreground and background.
|
||||
std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr) const noexcept
|
||||
{
|
||||
return LookupAttributeColors(attr, GetDefaultForeground(), GetDefaultBackground());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the colors of a particular text attribute, using our color table,
|
||||
// and the given default color values.
|
||||
// Arguments:
|
||||
// - attr: the TextAttribute to retrieve the foreground and background color of.
|
||||
// - defaultFg: the COLORREF to use for a default foreground color.
|
||||
// - defaultBg: the COLORREF to use for a default background color.
|
||||
// Return Value:
|
||||
// - The color values of the attribute's foreground and background.
|
||||
std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr, const COLORREF defaultFg, const COLORREF defaultBg) const noexcept
|
||||
{
|
||||
_blinkingState.RecordBlinkingUsage(attr);
|
||||
return attr.CalculateRgbColors(
|
||||
GetColorTable(),
|
||||
defaultFg,
|
||||
defaultBg,
|
||||
GetDefaultForegroundIndex(),
|
||||
GetDefaultBackgroundIndex(),
|
||||
IsScreenReversed(),
|
||||
_blinkingState.IsBlinkingFaint());
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@
|
|||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>copy $(SolutionDir)\dep\WinAppDriver\* $(OutDir)\</PostBuildEvent>
|
||||
<PostBuildEvent>copy "$(SolutionDir)\dep\WinAppDriver\*" "$(OutDir)\"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets" Condition="Exists('..\..\..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
@ -152,4 +152,4 @@
|
|||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Taef.10.60.210621002\build\Microsoft.Taef.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1499,12 +1499,6 @@ void DoSrvSetCursorStyle(SCREEN_INFORMATION& screenInfo,
|
|||
screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetType(cursorType);
|
||||
}
|
||||
|
||||
void DoSrvSetCursorColor(SCREEN_INFORMATION& screenInfo,
|
||||
const COLORREF cursorColor)
|
||||
{
|
||||
screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetColor(cursorColor);
|
||||
}
|
||||
|
||||
void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo,
|
||||
const std::wstring_view uri,
|
||||
const std::wstring_view params)
|
||||
|
@ -1963,115 +1957,6 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
|
|||
screenInfo.GetActiveBuffer().MoveToBottom();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieve the color table value at the specified index.
|
||||
// Arguments:
|
||||
// - index: the index in the table to retrieve.
|
||||
// - value: receives the RGB value for the color at that index in the table.
|
||||
// Return Value:
|
||||
// - E_INVALIDARG if index is >= 256, else S_OK
|
||||
[[nodiscard]] HRESULT DoSrvPrivateGetColorTableEntry(const size_t index, COLORREF& value) noexcept
|
||||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, index >= 256);
|
||||
try
|
||||
{
|
||||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
value = gci.GetColorTableEntry(index);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the color table value in index to the color specified in value.
|
||||
// Can be used to set the 256-color table as well as the 16-color table.
|
||||
// Arguments:
|
||||
// - index: the index in the table to change.
|
||||
// - value: the new RGB value to use for that index in the color table.
|
||||
// Return Value:
|
||||
// - E_INVALIDARG if index is >= 256, else S_OK
|
||||
// Notes:
|
||||
// Does not take a buffer parameter. The color table for a console and for
|
||||
// terminals as well is global, not per-screen-buffer.
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetColorTableEntry(const size_t index, const COLORREF value) noexcept
|
||||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, index >= 256);
|
||||
try
|
||||
{
|
||||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetColorTableEntry(index, value);
|
||||
|
||||
// Update the screen colors if we're not a pty
|
||||
// No need to force a redraw in pty mode.
|
||||
if (g.pRender && !gci.IsInVtIoMode())
|
||||
{
|
||||
g.pRender->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the default foreground color to the color specified in value.
|
||||
// Arguments:
|
||||
// - value: the new RGB value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetDefaultForegroundColor(const COLORREF value) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetDefaultForegroundColor(value);
|
||||
|
||||
// Update the screen colors if we're not a pty
|
||||
// No need to force a redraw in pty mode.
|
||||
if (g.pRender && !gci.IsInVtIoMode())
|
||||
{
|
||||
g.pRender->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the default background color to the color specified in value.
|
||||
// Arguments:
|
||||
// - value: the new RGB value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetDefaultBackgroundColor(const COLORREF value) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetDefaultBackgroundColor(value);
|
||||
|
||||
// Update the screen colors if we're not a pty
|
||||
// No need to force a redraw in pty mode.
|
||||
if (g.pRender && !gci.IsInVtIoMode())
|
||||
{
|
||||
g.pRender->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - A private API call for filling a region of the screen buffer.
|
||||
// Arguments:
|
||||
|
|
|
@ -36,8 +36,6 @@ void DoSrvPrivateUseMainScreenBuffer(SCREEN_INFORMATION& screenInfo);
|
|||
|
||||
void DoSrvSetCursorStyle(SCREEN_INFORMATION& screenInfo,
|
||||
const CursorType cursorType);
|
||||
void DoSrvSetCursorColor(SCREEN_INFORMATION& screenInfo,
|
||||
const COLORREF cursorColor);
|
||||
|
||||
void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo,
|
||||
const std::wstring_view uri,
|
||||
|
@ -63,13 +61,6 @@ void DoSrvPrivateInsertLines(const size_t count);
|
|||
|
||||
void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo);
|
||||
|
||||
[[nodiscard]] HRESULT DoSrvPrivateGetColorTableEntry(const size_t index, COLORREF& value) noexcept;
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetColorTableEntry(const size_t index, const COLORREF value) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetDefaultForegroundColor(const COLORREF value) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT DoSrvPrivateSetDefaultBackgroundColor(const COLORREF value) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT DoSrvPrivateFillRegion(SCREEN_INFORMATION& screenInfo,
|
||||
const COORD startPosition,
|
||||
const size_t fillLength,
|
||||
|
|
|
@ -552,21 +552,6 @@ bool ConhostInternalGetSet::PrivateSuppressResizeRepaint()
|
|||
return SUCCEEDED(DoSrvPrivateSuppressResizeRepaint());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the SetCursorStyle call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// SetCursorStyle is an internal-only "API" call that the vt commands can execute,
|
||||
// but it is not represented as a function call on our public API surface.
|
||||
// Arguments:
|
||||
// - cursorColor: The color to change the cursor to. INVALID_COLOR will revert
|
||||
// it to the legacy inverting behavior.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvSetCursorStyle). false otherwise.
|
||||
bool ConhostInternalGetSet::SetCursorColor(const COLORREF cursorColor)
|
||||
{
|
||||
DoSrvSetCursorColor(_io.GetActiveOutputBuffer(), cursorColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the IsConsolePty call directly into our Driver Message servicing call inside Conhost.exe
|
||||
// - NOTE: This ONE method behaves differently! The rest of the methods on this
|
||||
|
@ -608,54 +593,61 @@ bool ConhostInternalGetSet::MoveToBottom() const
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Connects the PrivateGetColorTableEntry call directly into our Driver Message servicing
|
||||
// call inside Conhost.exe
|
||||
// - Retrieves the value in the colortable at the specified index.
|
||||
// Arguments:
|
||||
// - index: the index in the table to retrieve.
|
||||
// - value: receives the RGB value for the color at that index in the table.
|
||||
// - tableIndex: the index of the color table to retrieve.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateGetColorTableEntry). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateGetColorTableEntry(const size_t index, COLORREF& value) const noexcept
|
||||
// - the COLORREF value for the color at that index in the table.
|
||||
COLORREF ConhostInternalGetSet::GetColorTableEntry(const size_t tableIndex) const noexcept
|
||||
try
|
||||
{
|
||||
return SUCCEEDED(DoSrvPrivateGetColorTableEntry(index, value));
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
|
||||
return gci.GetColorTableEntry(tableIndex);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return INVALID_COLOR;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Connects the PrivateSetColorTableEntry call directly into our Driver Message servicing
|
||||
// call inside Conhost.exe
|
||||
// - Updates the value in the colortable at index tableIndex to the new color
|
||||
// color. color is a COLORREF, format 0x00BBGGRR.
|
||||
// Arguments:
|
||||
// - index: the index in the table to change.
|
||||
// - value: the new RGB value to use for that index in the color table.
|
||||
// - tableIndex: the index of the color table to update.
|
||||
// - color: the new COLORREF to use as that color table value.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateSetColorTableEntry). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateSetColorTableEntry(const size_t index, const COLORREF value) const noexcept
|
||||
// - true if successful. false otherwise.
|
||||
bool ConhostInternalGetSet::SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept
|
||||
try
|
||||
{
|
||||
return SUCCEEDED(DoSrvPrivateSetColorTableEntry(index, value));
|
||||
}
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
|
||||
// Method Description:
|
||||
// - Connects the PrivateSetDefaultForeground call directly into our Driver Message servicing
|
||||
// call inside Conhost.exe
|
||||
// Arguments:
|
||||
// - value: the new RGB value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateSetDefaultForegroundColor). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateSetDefaultForeground(const COLORREF value) const noexcept
|
||||
{
|
||||
return SUCCEEDED(DoSrvPrivateSetDefaultForegroundColor(value));
|
||||
}
|
||||
gci.SetColorTableEntry(tableIndex, color);
|
||||
|
||||
// Method Description:
|
||||
// - Connects the PrivateSetDefaultBackground call directly into our Driver Message servicing
|
||||
// call inside Conhost.exe
|
||||
// Arguments:
|
||||
// - value: the new RGB value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// - true if successful (see DoSrvPrivateSetDefaultBackgroundColor). false otherwise.
|
||||
bool ConhostInternalGetSet::PrivateSetDefaultBackground(const COLORREF value) const noexcept
|
||||
{
|
||||
return SUCCEEDED(DoSrvPrivateSetDefaultBackgroundColor(value));
|
||||
// If we're setting the default foreground or background colors
|
||||
// we need to make sure the index is correctly set as well.
|
||||
if (tableIndex == TextColor::DEFAULT_FOREGROUND)
|
||||
{
|
||||
gci.SetDefaultForegroundIndex(TextColor::DEFAULT_FOREGROUND);
|
||||
}
|
||||
if (tableIndex == TextColor::DEFAULT_BACKGROUND)
|
||||
{
|
||||
gci.SetDefaultBackgroundIndex(TextColor::DEFAULT_BACKGROUND);
|
||||
}
|
||||
|
||||
// Update the screen colors if we're not a pty
|
||||
// No need to force a redraw in pty mode.
|
||||
if (g.pRender && !gci.IsInVtIoMode())
|
||||
{
|
||||
g.pRender->TriggerRedrawAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
CATCH_RETURN_FALSE()
|
||||
|
||||
// Routine Description:
|
||||
// - Connects the PrivateFillRegion call directly into our Driver Message servicing
|
||||
|
|
|
@ -101,7 +101,6 @@ public:
|
|||
|
||||
bool GetUserDefaultCursorStyle(CursorType& style) override;
|
||||
bool SetCursorStyle(CursorType const style) override;
|
||||
bool SetCursorColor(COLORREF const color) override;
|
||||
|
||||
bool PrivateRefreshWindow() override;
|
||||
|
||||
|
@ -119,12 +118,8 @@ public:
|
|||
|
||||
bool MoveToBottom() const override;
|
||||
|
||||
bool PrivateGetColorTableEntry(const size_t index, COLORREF& value) const noexcept override;
|
||||
bool PrivateSetColorTableEntry(const size_t index, const COLORREF value) const noexcept override;
|
||||
|
||||
bool PrivateSetDefaultForeground(const COLORREF value) const noexcept override;
|
||||
|
||||
bool PrivateSetDefaultBackground(const COLORREF value) const noexcept override;
|
||||
COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept override;
|
||||
bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept override;
|
||||
|
||||
bool PrivateFillRegion(const COORD startPosition,
|
||||
const size_t fillLength,
|
||||
|
|
|
@ -110,8 +110,6 @@ void RenderData::UnlockConsole() noexcept
|
|||
const TextAttribute RenderData::GetDefaultBrushColors() noexcept
|
||||
{
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
_defaultForeground = gci.GetDefaultForeground();
|
||||
_defaultBackground = gci.GetDefaultBackground();
|
||||
return gci.GetActiveOutputBuffer().GetAttributes();
|
||||
}
|
||||
|
||||
|
@ -226,8 +224,7 @@ ULONG RenderData::GetCursorPixelWidth() const noexcept
|
|||
COLORREF RenderData::GetCursorColor() const noexcept
|
||||
{
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto& cursor = gci.GetActiveOutputBuffer().GetTextBuffer().GetCursor();
|
||||
return cursor.GetColor();
|
||||
return gci.GetColorTableEntry(TextColor::CURSOR_COLOR);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -364,7 +361,7 @@ const std::vector<size_t> RenderData::GetPatternId(const COORD /*location*/) con
|
|||
std::pair<COLORREF, COLORREF> RenderData::GetAttributeColors(const TextAttribute& attr) const noexcept
|
||||
{
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
return gci.LookupAttributeColors(attr, _defaultForeground, _defaultBackground);
|
||||
return gci.LookupAttributeColors(attr);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
|
|
|
@ -72,8 +72,4 @@ public:
|
|||
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute attr);
|
||||
const bool IsUiaDataInitialized() const noexcept override { return true; }
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
COLORREF _defaultForeground = gsl::at(Microsoft::Console::Utils::CampbellColorTable(), 7);
|
||||
COLORREF _defaultBackground = gsl::at(Microsoft::Console::Utils::CampbellColorTable(), 0);
|
||||
};
|
||||
|
|
|
@ -123,7 +123,6 @@ SCREEN_INFORMATION::~SCREEN_INFORMATION()
|
|||
pScreen->_renderTarget);
|
||||
|
||||
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
pScreen->_textBuffer->GetCursor().SetColor(gci.GetCursorColor());
|
||||
pScreen->_textBuffer->GetCursor().SetType(gci.GetCursorType());
|
||||
|
||||
const NTSTATUS status = pScreen->_InitializeOutputStateMachine();
|
||||
|
@ -1630,29 +1629,6 @@ void SCREEN_INFORMATION::SetCursorInformation(const ULONG Size,
|
|||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - This routine sets the cursor color. Also updates the cursor information of
|
||||
// this buffer's main buffer, if this buffer is an alt buffer.
|
||||
// Arguments:
|
||||
// - Color - The new color to set the cursor to
|
||||
// - setMain - If true, propagate change to main buffer as well.
|
||||
// Return Value:
|
||||
// - None
|
||||
void SCREEN_INFORMATION::SetCursorColor(const unsigned int Color, const bool setMain) noexcept
|
||||
{
|
||||
Cursor& cursor = _textBuffer->GetCursor();
|
||||
|
||||
cursor.SetColor(Color);
|
||||
|
||||
// If we're an alt buffer, DON'T propagate this setting up to the main buffer.
|
||||
// We don't want to pollute that buffer with this state,
|
||||
// UNLESS we're getting called from the propsheet, then we DO want to update this.
|
||||
if (_psiMainBuffer && setMain)
|
||||
{
|
||||
_psiMainBuffer->SetCursorColor(Color);
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - This routine sets the cursor shape both in the data
|
||||
// structures and on the screen. Also updates the cursor information of
|
||||
|
@ -1908,7 +1884,7 @@ const SCREEN_INFORMATION& SCREEN_INFORMATION::GetMainBuffer() const
|
|||
auto& myCursor = GetTextBuffer().GetCursor();
|
||||
auto* const createdBuffer = *ppsiNewScreenBuffer;
|
||||
auto& altCursor = createdBuffer->GetTextBuffer().GetCursor();
|
||||
altCursor.SetStyle(myCursor.GetSize(), myCursor.GetColor(), myCursor.GetType());
|
||||
altCursor.SetStyle(myCursor.GetSize(), myCursor.GetType());
|
||||
altCursor.SetIsVisible(myCursor.IsVisible());
|
||||
altCursor.SetBlinkingAllowed(myCursor.IsBlinkingAllowed());
|
||||
// The new position should match the viewport-relative position of the main buffer.
|
||||
|
@ -2006,7 +1982,7 @@ void SCREEN_INFORMATION::UseMainScreenBuffer()
|
|||
// Copy the alt buffer's cursor style and visibility back to the main buffer.
|
||||
const auto& altCursor = psiAlt->GetTextBuffer().GetCursor();
|
||||
auto& mainCursor = psiMain->GetTextBuffer().GetCursor();
|
||||
mainCursor.SetStyle(altCursor.GetSize(), altCursor.GetColor(), altCursor.GetType());
|
||||
mainCursor.SetStyle(altCursor.GetSize(), altCursor.GetType());
|
||||
mainCursor.SetIsVisible(altCursor.IsVisible());
|
||||
mainCursor.SetBlinkingAllowed(altCursor.IsBlinkingAllowed());
|
||||
|
||||
|
|
|
@ -189,8 +189,6 @@ public:
|
|||
void SetCursorInformation(const ULONG Size,
|
||||
const bool Visible) noexcept;
|
||||
|
||||
void SetCursorColor(const unsigned int Color, const bool setMain = false) noexcept;
|
||||
|
||||
void SetCursorType(const CursorType Type, const bool setMain = false) noexcept;
|
||||
|
||||
void SetCursorDBMode(const bool DoubleCursor);
|
||||
|
|
|
@ -16,7 +16,6 @@ Selection::Selection() :
|
|||
_fSelectionVisible(false),
|
||||
_ulSavedCursorSize(0),
|
||||
_fSavedCursorVisible(false),
|
||||
_savedCursorColor(INVALID_COLOR),
|
||||
_savedCursorType(CursorType::Legacy),
|
||||
_dwSelectionFlags(0),
|
||||
_fLineSelection(true),
|
||||
|
|
|
@ -174,7 +174,6 @@ private:
|
|||
COORD _coordSavedCursorPosition;
|
||||
ULONG _ulSavedCursorSize;
|
||||
bool _fSavedCursorVisible;
|
||||
COLORREF _savedCursorColor;
|
||||
CursorType _savedCursorType;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
|
|
|
@ -168,7 +168,6 @@ void Selection::_SaveCursorData(const Cursor& cursor) noexcept
|
|||
_coordSavedCursorPosition = cursor.GetPosition();
|
||||
_ulSavedCursorSize = cursor.GetSize();
|
||||
_fSavedCursorVisible = cursor.IsVisible();
|
||||
_savedCursorColor = cursor.GetColor();
|
||||
_savedCursorType = cursor.GetType();
|
||||
}
|
||||
|
||||
|
@ -182,7 +181,6 @@ void Selection::_RestoreDataToCursor(Cursor& cursor) noexcept
|
|||
{
|
||||
cursor.SetSize(_ulSavedCursorSize);
|
||||
cursor.SetIsVisible(_fSavedCursorVisible);
|
||||
cursor.SetColor(_savedCursorColor);
|
||||
cursor.SetType(_savedCursorType);
|
||||
cursor.SetIsOn(true);
|
||||
cursor.SetPosition(_coordSavedCursorPosition);
|
||||
|
|
|
@ -124,10 +124,7 @@ public:
|
|||
COOKED_READ_DATA& CookedReadData() noexcept;
|
||||
void SetCookedReadData(COOKED_READ_DATA* readData) noexcept;
|
||||
|
||||
COLORREF GetDefaultForeground() const noexcept;
|
||||
COLORREF GetDefaultBackground() const noexcept;
|
||||
std::pair<COLORREF, COLORREF> LookupAttributeColors(const TextAttribute& attr) const noexcept;
|
||||
std::pair<COLORREF, COLORREF> LookupAttributeColors(const TextAttribute& attr, const COLORREF defaultFg, const COLORREF defaultBg) const noexcept;
|
||||
|
||||
void SetTitle(const std::wstring_view newTitle);
|
||||
void SetTitlePrefix(const std::wstring_view newTitlePrefix);
|
||||
|
|
|
@ -56,8 +56,8 @@ Settings::Settings() :
|
|||
_fScreenReversed(false),
|
||||
// window size pixels initialized below
|
||||
_fInterceptCopyPaste(0),
|
||||
_DefaultForeground(INVALID_COLOR),
|
||||
_DefaultBackground(INVALID_COLOR),
|
||||
_defaultForegroundIndex(TextColor::DARK_WHITE),
|
||||
_defaultBackgroundIndex(TextColor::DARK_BLACK),
|
||||
_fUseDx(UseDx::Disabled),
|
||||
_fCopyColor(false)
|
||||
{
|
||||
|
@ -78,11 +78,14 @@ Settings::Settings() :
|
|||
ZeroMemory((void*)&_FaceName, sizeof(_FaceName));
|
||||
wcscpy_s(_FaceName, DEFAULT_TT_FONT_FACENAME);
|
||||
|
||||
_CursorColor = Cursor::s_InvertCursorColor;
|
||||
_CursorType = CursorType::Legacy;
|
||||
|
||||
gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
|
||||
::Microsoft::Console::Utils::InitializeColorTable(tableView);
|
||||
|
||||
_colorTable.at(TextColor::DEFAULT_FOREGROUND) = INVALID_COLOR;
|
||||
_colorTable.at(TextColor::DEFAULT_BACKGROUND) = INVALID_COLOR;
|
||||
_colorTable.at(TextColor::CURSOR_COLOR) = INVALID_COLOR;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -229,11 +232,11 @@ void Settings::InitFromStateInfo(_In_ PCONSOLE_STATE_INFO pStateInfo)
|
|||
_fCtrlKeyShortcutsDisabled = pStateInfo->fCtrlKeyShortcutsDisabled;
|
||||
_bLineSelection = pStateInfo->fLineSelection;
|
||||
_bWindowAlpha = pStateInfo->bWindowTransparency;
|
||||
_CursorColor = pStateInfo->CursorColor;
|
||||
_CursorType = static_cast<CursorType>(pStateInfo->CursorType);
|
||||
_fInterceptCopyPaste = pStateInfo->InterceptCopyPaste;
|
||||
_DefaultForeground = pStateInfo->DefaultForeground;
|
||||
_DefaultBackground = pStateInfo->DefaultBackground;
|
||||
_colorTable.at(TextColor::DEFAULT_FOREGROUND) = pStateInfo->DefaultForeground;
|
||||
_colorTable.at(TextColor::DEFAULT_BACKGROUND) = pStateInfo->DefaultBackground;
|
||||
_colorTable.at(TextColor::CURSOR_COLOR) = pStateInfo->CursorColor;
|
||||
_TerminalScrolling = pStateInfo->TerminalScrolling;
|
||||
}
|
||||
|
||||
|
@ -274,11 +277,11 @@ CONSOLE_STATE_INFO Settings::CreateConsoleStateInfo() const
|
|||
csi.fCtrlKeyShortcutsDisabled = _fCtrlKeyShortcutsDisabled;
|
||||
csi.fLineSelection = _bLineSelection;
|
||||
csi.bWindowTransparency = _bWindowAlpha;
|
||||
csi.CursorColor = _CursorColor;
|
||||
csi.CursorType = static_cast<unsigned int>(_CursorType);
|
||||
csi.InterceptCopyPaste = _fInterceptCopyPaste;
|
||||
csi.DefaultForeground = _DefaultForeground;
|
||||
csi.DefaultBackground = _DefaultBackground;
|
||||
csi.DefaultForeground = _colorTable.at(TextColor::DEFAULT_FOREGROUND);
|
||||
csi.DefaultBackground = _colorTable.at(TextColor::DEFAULT_BACKGROUND);
|
||||
csi.CursorColor = _colorTable.at(TextColor::CURSOR_COLOR);
|
||||
csi.TerminalScrolling = _TerminalScrolling;
|
||||
return csi;
|
||||
}
|
||||
|
@ -330,16 +333,22 @@ void Settings::Validate()
|
|||
WI_ClearAllFlags(_wFillAttribute, ~(FG_ATTRS | BG_ATTRS));
|
||||
WI_ClearAllFlags(_wPopupFillAttribute, ~(FG_ATTRS | BG_ATTRS));
|
||||
|
||||
const auto defaultForeground = _colorTable.at(TextColor::DEFAULT_FOREGROUND);
|
||||
const auto defaultBackground = _colorTable.at(TextColor::DEFAULT_BACKGROUND);
|
||||
const auto cursorColor = _colorTable.at(TextColor::CURSOR_COLOR);
|
||||
|
||||
// If the extended color options are set to invalid values (all the same color), reset them.
|
||||
if (_CursorColor != Cursor::s_InvertCursorColor && _CursorColor == _DefaultBackground)
|
||||
if (cursorColor != INVALID_COLOR && cursorColor == defaultBackground)
|
||||
{
|
||||
_CursorColor = Cursor::s_InvertCursorColor;
|
||||
// INVALID_COLOR is used to represent "Invert Colors"
|
||||
_colorTable.at(TextColor::CURSOR_COLOR) = INVALID_COLOR;
|
||||
}
|
||||
|
||||
if (_DefaultForeground != INVALID_COLOR && _DefaultForeground == _DefaultBackground)
|
||||
if (defaultForeground != INVALID_COLOR && defaultForeground == defaultBackground)
|
||||
{
|
||||
// INVALID_COLOR is used as an "unset" sentinel in future attribute functions.
|
||||
_DefaultForeground = _DefaultBackground = INVALID_COLOR;
|
||||
_colorTable.at(TextColor::DEFAULT_FOREGROUND) = INVALID_COLOR;
|
||||
_colorTable.at(TextColor::DEFAULT_BACKGROUND) = INVALID_COLOR;
|
||||
// If the damaged settings _further_ propagated to the default fill attribute, fix it.
|
||||
if (_wFillAttribute == 0)
|
||||
{
|
||||
|
@ -351,6 +360,8 @@ void Settings::Validate()
|
|||
// At this point the default fill attributes are fully initialized
|
||||
// so we can pass on the final colors to the TextAttribute class.
|
||||
TextAttribute::SetLegacyDefaultAttributes(_wFillAttribute);
|
||||
// And calculate the position of the default colors in the color table.
|
||||
CalculateDefaultColorIndices();
|
||||
|
||||
FAIL_FAST_IF(!(_dwWindowSize.X > 0));
|
||||
FAIL_FAST_IF(!(_dwWindowSize.Y > 0));
|
||||
|
@ -760,21 +771,11 @@ COLORREF Settings::GetLegacyColorTableEntry(const size_t index) const
|
|||
return _colorTable.at(TextColor::TransposeLegacyIndex(index));
|
||||
}
|
||||
|
||||
COLORREF Settings::GetCursorColor() const noexcept
|
||||
{
|
||||
return _CursorColor;
|
||||
}
|
||||
|
||||
CursorType Settings::GetCursorType() const noexcept
|
||||
{
|
||||
return _CursorType;
|
||||
}
|
||||
|
||||
void Settings::SetCursorColor(const COLORREF CursorColor) noexcept
|
||||
{
|
||||
_CursorColor = CursorColor;
|
||||
}
|
||||
|
||||
void Settings::SetCursorType(const CursorType cursorType) noexcept
|
||||
{
|
||||
_CursorType = cursorType;
|
||||
|
@ -790,24 +791,35 @@ void Settings::SetInterceptCopyPaste(const bool interceptCopyPaste) noexcept
|
|||
_fInterceptCopyPaste = interceptCopyPaste;
|
||||
}
|
||||
|
||||
COLORREF Settings::GetDefaultForegroundColor() const noexcept
|
||||
void Settings::CalculateDefaultColorIndices() noexcept
|
||||
{
|
||||
return _DefaultForeground;
|
||||
const auto foregroundColor = _colorTable.at(TextColor::DEFAULT_FOREGROUND);
|
||||
const auto foregroundIndex = TextColor::TransposeLegacyIndex(_wFillAttribute & FG_ATTRS);
|
||||
_defaultForegroundIndex = foregroundColor != INVALID_COLOR ? TextColor::DEFAULT_FOREGROUND : foregroundIndex;
|
||||
|
||||
const auto backgroundColor = _colorTable.at(TextColor::DEFAULT_BACKGROUND);
|
||||
const auto backgroundIndex = TextColor::TransposeLegacyIndex((_wFillAttribute & BG_ATTRS) >> 4);
|
||||
_defaultBackgroundIndex = backgroundColor != INVALID_COLOR ? TextColor::DEFAULT_BACKGROUND : backgroundIndex;
|
||||
}
|
||||
|
||||
void Settings::SetDefaultForegroundColor(const COLORREF defaultForeground) noexcept
|
||||
size_t Settings::GetDefaultForegroundIndex() const noexcept
|
||||
{
|
||||
_DefaultForeground = defaultForeground;
|
||||
return _defaultForegroundIndex;
|
||||
}
|
||||
|
||||
COLORREF Settings::GetDefaultBackgroundColor() const noexcept
|
||||
void Settings::SetDefaultForegroundIndex(const size_t index) noexcept
|
||||
{
|
||||
return _DefaultBackground;
|
||||
_defaultForegroundIndex = index;
|
||||
}
|
||||
|
||||
void Settings::SetDefaultBackgroundColor(const COLORREF defaultBackground) noexcept
|
||||
size_t Settings::GetDefaultBackgroundIndex() const noexcept
|
||||
{
|
||||
_DefaultBackground = defaultBackground;
|
||||
return _defaultBackgroundIndex;
|
||||
}
|
||||
|
||||
void Settings::SetDefaultBackgroundIndex(const size_t index) noexcept
|
||||
{
|
||||
_defaultBackgroundIndex = index;
|
||||
}
|
||||
|
||||
bool Settings::IsTerminalScrolling() const noexcept
|
||||
|
|
|
@ -167,7 +167,7 @@ public:
|
|||
void SetHistoryNoDup(const bool fHistoryNoDup);
|
||||
|
||||
// The first 16 items of the color table are the same as the 16-color palette.
|
||||
inline const std::array<COLORREF, XTERM_COLOR_TABLE_SIZE>& GetColorTable() const noexcept
|
||||
inline const std::array<COLORREF, TextColor::TABLE_SIZE>& GetColorTable() const noexcept
|
||||
{
|
||||
return _colorTable;
|
||||
}
|
||||
|
@ -177,20 +177,17 @@ public:
|
|||
void SetLegacyColorTableEntry(const size_t index, const COLORREF ColorValue);
|
||||
COLORREF GetLegacyColorTableEntry(const size_t index) const;
|
||||
|
||||
COLORREF GetCursorColor() const noexcept;
|
||||
CursorType GetCursorType() const noexcept;
|
||||
|
||||
void SetCursorColor(const COLORREF CursorColor) noexcept;
|
||||
void SetCursorType(const CursorType cursorType) noexcept;
|
||||
|
||||
bool GetInterceptCopyPaste() const noexcept;
|
||||
void SetInterceptCopyPaste(const bool interceptCopyPaste) noexcept;
|
||||
|
||||
COLORREF GetDefaultForegroundColor() const noexcept;
|
||||
void SetDefaultForegroundColor(const COLORREF defaultForeground) noexcept;
|
||||
|
||||
COLORREF GetDefaultBackgroundColor() const noexcept;
|
||||
void SetDefaultBackgroundColor(const COLORREF defaultBackground) noexcept;
|
||||
void CalculateDefaultColorIndices() noexcept;
|
||||
size_t GetDefaultForegroundIndex() const noexcept;
|
||||
void SetDefaultForegroundIndex(const size_t index) noexcept;
|
||||
size_t GetDefaultBackgroundIndex() const noexcept;
|
||||
void SetDefaultBackgroundIndex(const size_t index) noexcept;
|
||||
|
||||
bool IsTerminalScrolling() const noexcept;
|
||||
void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept;
|
||||
|
@ -242,20 +239,19 @@ private:
|
|||
UseDx _fUseDx;
|
||||
bool _fCopyColor;
|
||||
|
||||
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
|
||||
std::array<COLORREF, TextColor::TABLE_SIZE> _colorTable;
|
||||
|
||||
// this is used for the special STARTF_USESIZE mode.
|
||||
bool _fUseWindowSizePixels;
|
||||
COORD _dwWindowSizePixels;
|
||||
|
||||
// Technically a COLORREF, but using INVALID_COLOR as "Invert Colors"
|
||||
unsigned int _CursorColor;
|
||||
CursorType _CursorType;
|
||||
|
||||
bool _fInterceptCopyPaste;
|
||||
|
||||
COLORREF _DefaultForeground;
|
||||
COLORREF _DefaultBackground;
|
||||
size_t _defaultForegroundIndex;
|
||||
size_t _defaultBackgroundIndex;
|
||||
|
||||
bool _TerminalScrolling;
|
||||
friend class RegistrySerialization;
|
||||
};
|
||||
|
|
|
@ -67,9 +67,10 @@ class ConptyOutputTests
|
|||
// Set up some sane defaults
|
||||
auto& g = ServiceLocator::LocateGlobals();
|
||||
auto& gci = g.getConsoleInformation();
|
||||
gci.SetDefaultForegroundColor(INVALID_COLOR);
|
||||
gci.SetDefaultBackgroundColor(INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
|
||||
gci.SetFillAttribute(0x07); // DARK_WHITE on DARK_BLACK
|
||||
gci.CalculateDefaultColorIndices();
|
||||
|
||||
m_state->PrepareNewTextBufferInfo(true, TerminalViewWidth, TerminalViewHeight);
|
||||
auto& currentBuffer = gci.GetActiveOutputBuffer();
|
||||
|
|
|
@ -59,9 +59,10 @@ class ScreenBufferTests
|
|||
{
|
||||
// Set up some sane defaults
|
||||
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
gci.SetDefaultForegroundColor(INVALID_COLOR);
|
||||
gci.SetDefaultBackgroundColor(INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, INVALID_COLOR);
|
||||
gci.SetFillAttribute(0x07); // DARK_WHITE on DARK_BLACK
|
||||
gci.CalculateDefaultColorIndices();
|
||||
|
||||
m_state->PrepareNewTextBufferInfo();
|
||||
auto& currentBuffer = gci.GetActiveOutputBuffer();
|
||||
|
@ -359,12 +360,11 @@ void ScreenBufferTests::AlternateBufferCursorInheritanceTest()
|
|||
auto mainCursorPos = COORD{ 3, 5 };
|
||||
auto mainCursorVisible = false;
|
||||
auto mainCursorSize = 33u;
|
||||
auto mainCursorColor = RGB(1, 2, 3);
|
||||
auto mainCursorType = CursorType::DoubleUnderscore;
|
||||
auto mainCursorBlinking = false;
|
||||
mainCursor.SetPosition(mainCursorPos);
|
||||
mainCursor.SetIsVisible(mainCursorVisible);
|
||||
mainCursor.SetStyle(mainCursorSize, mainCursorColor, mainCursorType);
|
||||
mainCursor.SetStyle(mainCursorSize, mainCursorType);
|
||||
mainCursor.SetBlinkingAllowed(mainCursorBlinking);
|
||||
|
||||
Log::Comment(L"Switch to the alternate buffer.");
|
||||
|
@ -379,7 +379,6 @@ void ScreenBufferTests::AlternateBufferCursorInheritanceTest()
|
|||
VERIFY_ARE_EQUAL(mainCursorVisible, altCursor.IsVisible());
|
||||
Log::Comment(L"Confirm the cursor style is inherited from the main buffer.");
|
||||
VERIFY_ARE_EQUAL(mainCursorSize, altCursor.GetSize());
|
||||
VERIFY_ARE_EQUAL(mainCursorColor, altCursor.GetColor());
|
||||
VERIFY_ARE_EQUAL(mainCursorType, altCursor.GetType());
|
||||
VERIFY_ARE_EQUAL(mainCursorBlinking, altCursor.IsBlinkingAllowed());
|
||||
|
||||
|
@ -387,12 +386,11 @@ void ScreenBufferTests::AlternateBufferCursorInheritanceTest()
|
|||
auto altCursorPos = COORD{ 5, 3 };
|
||||
auto altCursorVisible = true;
|
||||
auto altCursorSize = 66u;
|
||||
auto altCursorColor = RGB(3, 2, 1);
|
||||
auto altCursorType = CursorType::EmptyBox;
|
||||
auto altCursorBlinking = true;
|
||||
altCursor.SetPosition(altCursorPos);
|
||||
altCursor.SetIsVisible(altCursorVisible);
|
||||
altCursor.SetStyle(altCursorSize, altCursorColor, altCursorType);
|
||||
altCursor.SetStyle(altCursorSize, altCursorType);
|
||||
altCursor.SetBlinkingAllowed(altCursorBlinking);
|
||||
|
||||
Log::Comment(L"Switch back to the main buffer.");
|
||||
|
@ -406,7 +404,6 @@ void ScreenBufferTests::AlternateBufferCursorInheritanceTest()
|
|||
VERIFY_ARE_EQUAL(altCursorVisible, mainCursor.IsVisible());
|
||||
Log::Comment(L"Confirm the cursor style is inherited from the alt buffer.");
|
||||
VERIFY_ARE_EQUAL(altCursorSize, mainCursor.GetSize());
|
||||
VERIFY_ARE_EQUAL(altCursorColor, mainCursor.GetColor());
|
||||
VERIFY_ARE_EQUAL(altCursorType, mainCursor.GetType());
|
||||
VERIFY_ARE_EQUAL(altCursorBlinking, mainCursor.IsBlinkingAllowed());
|
||||
}
|
||||
|
@ -1388,8 +1385,9 @@ void ScreenBufferTests::VtScrollMarginsNewlineColor()
|
|||
|
||||
const COLORREF yellow = RGB(255, 255, 0);
|
||||
const COLORREF magenta = RGB(255, 0, 255);
|
||||
gci.SetDefaultForegroundColor(yellow);
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, yellow);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
const TextAttribute defaultAttrs = {};
|
||||
si.SetAttributes(defaultAttrs);
|
||||
|
||||
|
@ -1741,7 +1739,6 @@ void ScreenBufferTests::ResizeCursorUnchanged()
|
|||
// Get initial cursor values
|
||||
const CursorType initialType = initialCursor.GetType();
|
||||
const auto initialSize = initialCursor.GetSize();
|
||||
const COLORREF initialColor = initialCursor.GetColor();
|
||||
|
||||
// set our wrap mode accordingly - ResizeScreenBuffer will be smart enough
|
||||
// to call the appropriate implementation
|
||||
|
@ -1756,10 +1753,8 @@ void ScreenBufferTests::ResizeCursorUnchanged()
|
|||
const auto& finalCursor = si.GetTextBuffer().GetCursor();
|
||||
const CursorType finalType = finalCursor.GetType();
|
||||
const auto finalSize = finalCursor.GetSize();
|
||||
const COLORREF finalColor = finalCursor.GetColor();
|
||||
|
||||
VERIFY_ARE_EQUAL(initialType, finalType);
|
||||
VERIFY_ARE_EQUAL(initialColor, finalColor);
|
||||
VERIFY_ARE_EQUAL(initialSize, finalSize);
|
||||
}
|
||||
|
||||
|
@ -2122,7 +2117,6 @@ void ScreenBufferTests::TestAltBufferCursorState()
|
|||
// Validate that the cursor state was copied appropriately into the
|
||||
// alternate buffer
|
||||
VERIFY_ARE_EQUAL(mainCursor.GetSize(), altCursor.GetSize());
|
||||
VERIFY_ARE_EQUAL(mainCursor.GetColor(), altCursor.GetColor());
|
||||
VERIFY_ARE_EQUAL(mainCursor.GetType(), altCursor.GetType());
|
||||
}
|
||||
}
|
||||
|
@ -2259,8 +2253,9 @@ void ScreenBufferTests::SetDefaultsIndividuallyBothDefault()
|
|||
COLORREF brightGreen = gci.GetColorTableEntry(TextColor::BRIGHT_GREEN);
|
||||
COLORREF darkBlue = gci.GetColorTableEntry(TextColor::DARK_BLUE);
|
||||
|
||||
gci.SetDefaultForegroundColor(yellow);
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, yellow);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Write 6 X's:"));
|
||||
|
@ -2361,8 +2356,9 @@ void ScreenBufferTests::SetDefaultsTogether()
|
|||
COLORREF yellow = RGB(255, 255, 0);
|
||||
COLORREF color250 = gci.GetColorTableEntry(250);
|
||||
|
||||
gci.SetDefaultForegroundColor(yellow);
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, yellow);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Write 6 X's:"));
|
||||
|
@ -2432,8 +2428,9 @@ void ScreenBufferTests::ReverseResetWithDefaultBackground()
|
|||
|
||||
COLORREF magenta = RGB(255, 0, 255);
|
||||
|
||||
gci.SetDefaultForegroundColor(INVALID_COLOR);
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, INVALID_COLOR);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Write 3 X's:"));
|
||||
|
@ -2501,7 +2498,8 @@ void ScreenBufferTests::BackspaceDefaultAttrs()
|
|||
|
||||
COLORREF magenta = RGB(255, 0, 255);
|
||||
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Write 2 X's, then backspace one."));
|
||||
|
@ -2564,7 +2562,8 @@ void ScreenBufferTests::BackspaceDefaultAttrsWriteCharsLegacy()
|
|||
|
||||
COLORREF magenta = RGB(255, 0, 255);
|
||||
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Write 2 X's, then backspace one."));
|
||||
|
@ -2632,7 +2631,8 @@ void ScreenBufferTests::BackspaceDefaultAttrsInPrompt()
|
|||
|
||||
COLORREF magenta = RGB(255, 0, 255);
|
||||
|
||||
gci.SetDefaultBackgroundColor(magenta);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, magenta);
|
||||
gci.CalculateDefaultColorIndices();
|
||||
si.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
TextAttribute expectedDefaults{};
|
||||
|
||||
|
@ -2889,15 +2889,15 @@ void ScreenBufferTests::SetDefaultForegroundColor()
|
|||
|
||||
StateMachine& stateMachine = mainBuffer.GetStateMachine();
|
||||
|
||||
COLORREF originalColor = gci.GetDefaultForegroundColor();
|
||||
COLORREF newColor = gci.GetDefaultForegroundColor();
|
||||
COLORREF originalColor = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
COLORREF newColor = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
COLORREF testColor = RGB(0x33, 0x66, 0x99);
|
||||
VERIFY_ARE_NOT_EQUAL(originalColor, testColor);
|
||||
|
||||
Log::Comment(L"Valid Hexadecimal Notation");
|
||||
stateMachine.ProcessString(L"\x1b]10;rgb:33/66/99\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultForegroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
VERIFY_ARE_EQUAL(testColor, newColor);
|
||||
|
||||
Log::Comment(L"Valid Hexadecimal Notation");
|
||||
|
@ -2905,7 +2905,7 @@ void ScreenBufferTests::SetDefaultForegroundColor()
|
|||
testColor = RGB(0xff, 0xff, 0xff);
|
||||
stateMachine.ProcessString(L"\x1b]10;rgb:ff/ff/ff\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultForegroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
VERIFY_ARE_EQUAL(testColor, newColor);
|
||||
|
||||
Log::Comment(L"Invalid syntax");
|
||||
|
@ -2913,7 +2913,7 @@ void ScreenBufferTests::SetDefaultForegroundColor()
|
|||
testColor = RGB(153, 102, 51);
|
||||
stateMachine.ProcessString(L"\x1b]10;99/66/33\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultForegroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
VERIFY_ARE_NOT_EQUAL(testColor, newColor);
|
||||
// it will, in fact leave the color the way it was
|
||||
VERIFY_ARE_EQUAL(originalColor, newColor);
|
||||
|
@ -2934,15 +2934,15 @@ void ScreenBufferTests::SetDefaultBackgroundColor()
|
|||
|
||||
StateMachine& stateMachine = mainBuffer.GetStateMachine();
|
||||
|
||||
COLORREF originalColor = gci.GetDefaultBackgroundColor();
|
||||
COLORREF newColor = gci.GetDefaultBackgroundColor();
|
||||
COLORREF originalColor = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
COLORREF newColor = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
COLORREF testColor = RGB(0x33, 0x66, 0x99);
|
||||
VERIFY_ARE_NOT_EQUAL(originalColor, testColor);
|
||||
|
||||
Log::Comment(L"Valid Hexadecimal Notation");
|
||||
stateMachine.ProcessString(L"\x1b]11;rgb:33/66/99\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultBackgroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
VERIFY_ARE_EQUAL(testColor, newColor);
|
||||
|
||||
Log::Comment(L"Valid Hexadecimal Notation");
|
||||
|
@ -2950,7 +2950,7 @@ void ScreenBufferTests::SetDefaultBackgroundColor()
|
|||
testColor = RGB(0xff, 0xff, 0xff);
|
||||
stateMachine.ProcessString(L"\x1b]11;rgb:ff/ff/ff\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultBackgroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
VERIFY_ARE_EQUAL(testColor, newColor);
|
||||
|
||||
Log::Comment(L"Invalid Syntax");
|
||||
|
@ -2958,7 +2958,7 @@ void ScreenBufferTests::SetDefaultBackgroundColor()
|
|||
testColor = RGB(153, 102, 51);
|
||||
stateMachine.ProcessString(L"\x1b]11;99/66/33\x1b\\");
|
||||
|
||||
newColor = gci.GetDefaultBackgroundColor();
|
||||
newColor = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
VERIFY_ARE_NOT_EQUAL(testColor, newColor);
|
||||
// it will, in fact leave the color the way it was
|
||||
VERIFY_ARE_EQUAL(originalColor, newColor);
|
||||
|
|
|
@ -37,4 +37,3 @@ enum class CursorType : unsigned int
|
|||
constexpr COLORREF INVALID_COLOR = 0xffffffff;
|
||||
|
||||
constexpr WORD COLOR_TABLE_SIZE = 16;
|
||||
constexpr WORD XTERM_COLOR_TABLE_SIZE = 256;
|
||||
|
|
|
@ -3,130 +3,136 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#ifdef __cpp_concepts
|
||||
#define TIL_ENUMSET_VARARG template<std::same_as<T>... Args>
|
||||
#else
|
||||
#define TIL_ENUMSET_VARARG template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<T, Args>...>>>
|
||||
#endif
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
// By design, this class hides several methods in the std::bitset class
|
||||
// so they can be called with an enum parameter instead of a size_t, so
|
||||
// we need to disable the "hides a non-virtual function" warning.
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26434)
|
||||
|
||||
// til::enumset is a subclass of std::bitset, storing a fixed size array of
|
||||
// boolean elements, the positions in the array being identified by values
|
||||
// from a given enumerated type. By default it holds the same number of
|
||||
// bits as a size_t value.
|
||||
template<typename Type, size_t Bits = std::numeric_limits<size_t>::digits>
|
||||
class enumset : public std::bitset<Bits>
|
||||
// til::enumset stores a fixed size array of boolean elements, the positions
|
||||
// in the array being identified by values from a given enumerated type.
|
||||
// Position N corresponds to bit 1<<N in the UnderlyingType integer.
|
||||
//
|
||||
// If you only need 32 positions for your T, UnderlyingType can be set uint32_t.
|
||||
// It defaults to uintptr_t allowing you to set as many positions as a pointer has bits.
|
||||
// This class doesn't statically assert that your given position fits into UnderlyingType.
|
||||
template<typename T, typename UnderlyingType = uintptr_t>
|
||||
class enumset
|
||||
{
|
||||
using _base = std::bitset<Bits>;
|
||||
static_assert(std::is_unsigned_v<UnderlyingType>);
|
||||
|
||||
public:
|
||||
using reference = typename _base::reference;
|
||||
|
||||
enumset() = default;
|
||||
|
||||
// Method Description:
|
||||
// - Constructs a new bitset with the given list of positions set to true.
|
||||
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
|
||||
constexpr enumset(const Args... positions) noexcept :
|
||||
_base((... | (1ULL << static_cast<size_t>(positions))))
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr enumset(Args... positions) noexcept :
|
||||
_data{ to_underlying(positions...) }
|
||||
{
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the value of the bit at the given position.
|
||||
constexpr bool operator[](const Type pos) const
|
||||
// - Returns the underlying bit positions as a copy.
|
||||
constexpr UnderlyingType bits() const noexcept
|
||||
{
|
||||
return _base::operator[](static_cast<size_t>(pos));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns a reference to the bit at the given position.
|
||||
reference operator[](const Type pos)
|
||||
{
|
||||
return _base::operator[](static_cast<size_t>(pos));
|
||||
return _data;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns the value of the bit at the given position.
|
||||
// Throws std::out_of_range if it is not a valid position
|
||||
// in the bitset.
|
||||
bool test(const Type pos) const
|
||||
constexpr bool test(const T pos) const noexcept
|
||||
{
|
||||
return _base::test(static_cast<size_t>(pos));
|
||||
const auto mask = to_underlying(pos);
|
||||
return (_data & mask) != 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if any of the bits are set to true.
|
||||
bool any() const noexcept
|
||||
constexpr bool any() const noexcept
|
||||
{
|
||||
return _base::any();
|
||||
return _data != 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if any of the bits in the given positions are true.
|
||||
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
|
||||
bool any(const Args... positions) const noexcept
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr bool any(Args... positions) const noexcept
|
||||
{
|
||||
return (enumset{ positions... } & *this) != 0;
|
||||
const auto mask = to_underlying(positions...);
|
||||
return (_data & mask) != 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if all of the bits are set to true.
|
||||
bool all() const noexcept
|
||||
constexpr bool all() const noexcept
|
||||
{
|
||||
return _base::all();
|
||||
return _data == ~UnderlyingType{ 0 };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if all of the bits in the given positions are true.
|
||||
template<typename... Args, typename = std::enable_if_t<std::conjunction_v<std::is_same<Type, Args>...>>>
|
||||
bool all(const Args... positions) const noexcept
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr bool all(Args... positions) const noexcept
|
||||
{
|
||||
return (enumset{ positions... } & *this) == enumset{ positions... };
|
||||
const auto mask = to_underlying(positions...);
|
||||
return (_data & mask) == mask;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets the bit in the given position to the specified value.
|
||||
enumset& set(const Type pos, const bool val = true)
|
||||
// - Sets all of the bits in the given positions to true.
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr enumset& set(Args... positions) noexcept
|
||||
{
|
||||
_base::set(static_cast<size_t>(pos), val);
|
||||
_data |= to_underlying(positions...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resets the bit in the given position to false.
|
||||
enumset& reset(const Type pos)
|
||||
// - Sets the bit in the given position to the specified value.
|
||||
constexpr enumset& set(const T pos, const bool val) noexcept
|
||||
{
|
||||
_base::reset(static_cast<size_t>(pos));
|
||||
const auto mask = to_underlying(pos);
|
||||
// false == 0 --> UnderlyingType(-0) == 0b0000...
|
||||
// true == 1 --> UnderlyingType(-1) == 0b1111...
|
||||
#pragma warning(suppress : 4804) // '-': unsafe use of type 'bool' in operation
|
||||
_data = (_data & ~mask) | (-val & mask);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resets all of the bits in the given positions to false.
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr enumset& reset(Args... positions) noexcept
|
||||
{
|
||||
_data &= ~to_underlying(positions...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Flips the bit at the given position.
|
||||
enumset& flip(const Type pos)
|
||||
TIL_ENUMSET_VARARG
|
||||
constexpr enumset& flip(Args... positions) noexcept
|
||||
{
|
||||
_base::flip(static_cast<size_t>(pos));
|
||||
_data ^= to_underlying(positions...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets all of the bits in the given positions to true.
|
||||
private:
|
||||
template<typename... Args>
|
||||
enumset& set_all(const Args... positions)
|
||||
static constexpr UnderlyingType to_underlying(Args... positions) noexcept
|
||||
{
|
||||
return (..., set(positions));
|
||||
return ((UnderlyingType{ 1 } << static_cast<UnderlyingType>(positions)) | ...);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resets all of the bits in the given positions to false.
|
||||
template<typename... Args>
|
||||
enumset& reset_all(const Args... positions)
|
||||
template<>
|
||||
static constexpr UnderlyingType to_underlying() noexcept
|
||||
{
|
||||
return (..., reset(positions));
|
||||
return 0;
|
||||
}
|
||||
|
||||
UnderlyingType _data{};
|
||||
};
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
|
|
@ -208,10 +208,8 @@ void Clipboard::StoreSelectionToClipboard(bool const copyFormatting)
|
|||
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto& buffer = gci.GetActiveOutputBuffer().GetTextBuffer();
|
||||
|
||||
const auto defaultForeground = gci.GetDefaultForeground();
|
||||
const auto defaultBackground = gci.GetDefaultBackground();
|
||||
const auto GetAttributeColors = [=, &gci](const auto& attr) {
|
||||
return gci.LookupAttributeColors(attr, defaultForeground, defaultBackground);
|
||||
return gci.LookupAttributeColors(attr);
|
||||
};
|
||||
|
||||
bool includeCRLF, trimTrailingWhitespace;
|
||||
|
@ -276,9 +274,10 @@ void Clipboard::CopyTextToSystemClipboard(const TextBuffer::TextAndColor& rows,
|
|||
|
||||
if (fAlsoCopyFormatting)
|
||||
{
|
||||
const auto& fontData = ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer().GetCurrentFont();
|
||||
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto& fontData = gci.GetActiveOutputBuffer().GetCurrentFont();
|
||||
int const iFontHeightPoints = fontData.GetUnscaledSize().Y * 72 / ServiceLocator::LocateGlobals().dpi;
|
||||
const COLORREF bgColor = ServiceLocator::LocateGlobals().getConsoleInformation().GetDefaultBackground();
|
||||
const COLORREF bgColor = gci.GetColorTableEntry(gci.GetDefaultBackgroundIndex());
|
||||
|
||||
std::string HTMLToPlaceOnClip = TextBuffer::GenHTML(rows, iFontHeightPoints, fontData.GetFaceName(), bgColor);
|
||||
CopyToSystemClipboard(HTMLToPlaceOnClip, L"HTML Format");
|
||||
|
|
|
@ -315,7 +315,7 @@ void Menu::s_ShowPropertiesDialog(HWND const hwnd, BOOL const Defaults)
|
|||
|
||||
const Cursor& cursor = ScreenInfo.GetTextBuffer().GetCursor();
|
||||
pStateInfo->CursorSize = cursor.GetSize();
|
||||
pStateInfo->CursorColor = cursor.GetColor();
|
||||
pStateInfo->CursorColor = gci.GetColorTableEntry(TextColor::CURSOR_COLOR);
|
||||
pStateInfo->CursorType = static_cast<unsigned int>(cursor.GetType());
|
||||
|
||||
// Retrieve small icon for use in displaying the dialog
|
||||
|
@ -376,8 +376,8 @@ void Menu::s_ShowPropertiesDialog(HWND const hwnd, BOOL const Defaults)
|
|||
pStateInfo->InterceptCopyPaste = gci.GetInterceptCopyPaste();
|
||||
|
||||
// Get the properties from the settings
|
||||
pStateInfo->DefaultForeground = gci.GetDefaultForegroundColor();
|
||||
pStateInfo->DefaultBackground = gci.GetDefaultBackgroundColor();
|
||||
pStateInfo->DefaultForeground = gci.GetColorTableEntry(TextColor::DEFAULT_FOREGROUND);
|
||||
pStateInfo->DefaultBackground = gci.GetColorTableEntry(TextColor::DEFAULT_BACKGROUND);
|
||||
|
||||
pStateInfo->TerminalScrolling = gci.IsTerminalScrolling();
|
||||
// end console v2 properties
|
||||
|
@ -461,13 +461,12 @@ void Menu::s_PropertiesUpdate(PCONSOLE_STATE_INFO pStateInfo)
|
|||
|
||||
// Set the cursor properties in the Settings
|
||||
const auto cursorType = static_cast<CursorType>(pStateInfo->CursorType);
|
||||
gci.SetCursorColor(pStateInfo->CursorColor);
|
||||
gci.SetCursorType(cursorType);
|
||||
gci.SetColorTableEntry(TextColor::CURSOR_COLOR, pStateInfo->CursorColor);
|
||||
|
||||
// Then also apply them to the buffer's cursor
|
||||
ScreenInfo.SetCursorInformation(pStateInfo->CursorSize,
|
||||
ScreenInfo.GetTextBuffer().GetCursor().IsVisible());
|
||||
ScreenInfo.SetCursorColor(pStateInfo->CursorColor, true);
|
||||
ScreenInfo.SetCursorType(cursorType, true);
|
||||
|
||||
gci.SetTerminalScrolling(pStateInfo->TerminalScrolling);
|
||||
|
@ -579,11 +578,13 @@ void Menu::s_PropertiesUpdate(PCONSOLE_STATE_INFO pStateInfo)
|
|||
gci.SetFillAttribute(pStateInfo->ScreenAttributes);
|
||||
gci.SetPopupFillAttribute(pStateInfo->PopupAttributes);
|
||||
// Store our updated Default Color values
|
||||
gci.SetDefaultForegroundColor(pStateInfo->DefaultForeground);
|
||||
gci.SetDefaultBackgroundColor(pStateInfo->DefaultBackground);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, pStateInfo->DefaultForeground);
|
||||
gci.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, pStateInfo->DefaultBackground);
|
||||
|
||||
// Make sure the updated fill attributes are passed on to the TextAttribute class.
|
||||
TextAttribute::SetLegacyDefaultAttributes(pStateInfo->ScreenAttributes);
|
||||
// And recalculate the position of the default colors in the color table.
|
||||
gci.CalculateDefaultColorIndices();
|
||||
|
||||
// Set the screen info's default text attributes to defaults -
|
||||
ScreenInfo.SetDefaultAttributes({}, TextAttribute{ gci.GetPopupFillAttribute() });
|
||||
|
|
|
@ -78,8 +78,10 @@
|
|||
<AdditionalIncludeDirectories>$(IntermediateOutputPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- If you don't include a '.' at the end of the $(IntermediateOutputPath),
|
||||
mc.exe will get confused by the trailing slash. -->
|
||||
<Target Name="MessageCompile" Inputs="@(MessageCompile)" Outputs="$(IntermediateOutputPath)\%(MessageCompile.Filename).h" BeforeTargets="ClCompile">
|
||||
<Exec Command="mc.exe /h $(IntermediateOutputPath) /r $(IntermediateOutputPath) @(MessageCompile)" />
|
||||
<Exec Command="mc.exe /h "$(IntermediateOutputPath)." /r "$(IntermediateOutputPath)." @(MessageCompile)" />
|
||||
</Target>
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="..\common.build.post.props" />
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#pragma hdrstop
|
||||
|
||||
#define SET_FIELD_AND_SIZE(x) FIELD_OFFSET(Settings, x), RTL_FIELD_SIZE(Settings, x)
|
||||
#define SET_FIELD_AND_SIZE(x) UFIELD_OFFSET(Settings, x), RTL_FIELD_SIZE(Settings, x)
|
||||
|
||||
#define NT_TESTNULL(var) (((var) == nullptr) ? STATUS_NO_MEMORY : STATUS_SUCCESS)
|
||||
|
||||
|
@ -57,14 +57,14 @@ const RegistrySerialization::_RegPropertyMap RegistrySerialization::s_PropertyMa
|
|||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_TRIMZEROHEADINGS, SET_FIELD_AND_SIZE(_fTrimLeadingZeros) },
|
||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_ENABLE_COLOR_SELECTION, SET_FIELD_AND_SIZE(_fEnableColorSelection) },
|
||||
{ _RegPropertyType::Coordinate, CONSOLE_REGISTRY_WINDOWPOS, SET_FIELD_AND_SIZE(_dwWindowOrigin) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_CURSORCOLOR, SET_FIELD_AND_SIZE(_CursorColor) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_CURSORTYPE, SET_FIELD_AND_SIZE(_CursorType) },
|
||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_INTERCEPTCOPYPASTE, SET_FIELD_AND_SIZE(_fInterceptCopyPaste) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTFOREGROUND, SET_FIELD_AND_SIZE(_DefaultForeground) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTBACKGROUND, SET_FIELD_AND_SIZE(_DefaultBackground) },
|
||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_TERMINALSCROLLING, SET_FIELD_AND_SIZE(_TerminalScrolling) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) },
|
||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) }
|
||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTFOREGROUND, SET_FIELD_AND_SIZE(_colorTable[TextColor::DEFAULT_FOREGROUND]) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTBACKGROUND, SET_FIELD_AND_SIZE(_colorTable[TextColor::DEFAULT_BACKGROUND]) },
|
||||
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_CURSORCOLOR, SET_FIELD_AND_SIZE(_colorTable[TextColor::CURSOR_COLOR]) }
|
||||
|
||||
};
|
||||
const size_t RegistrySerialization::s_PropertyMappingsSize = ARRAYSIZE(s_PropertyMappings);
|
||||
|
|
|
@ -13,7 +13,8 @@ FontInfo::FontInfo(const std::wstring_view& faceName,
|
|||
const bool fSetDefaultRasterFont /* = false */) noexcept :
|
||||
FontInfoBase(faceName, family, weight, fSetDefaultRasterFont, codePage),
|
||||
_coordSize(coordSize),
|
||||
_coordSizeUnscaled(coordSize)
|
||||
_coordSizeUnscaled(coordSize),
|
||||
_didFallback(false)
|
||||
{
|
||||
ValidateFont();
|
||||
}
|
||||
|
@ -51,6 +52,16 @@ void FontInfo::SetFromEngine(const std::wstring_view& faceName,
|
|||
_ValidateCoordSize();
|
||||
}
|
||||
|
||||
bool FontInfo::GetFallback() const noexcept
|
||||
{
|
||||
return _didFallback;
|
||||
}
|
||||
|
||||
void FontInfo::SetFallback(const bool didFallback) noexcept
|
||||
{
|
||||
_didFallback = didFallback;
|
||||
}
|
||||
|
||||
void FontInfo::ValidateFont() noexcept
|
||||
{
|
||||
_ValidateCoordSize();
|
||||
|
|
|
@ -20,8 +20,8 @@ using namespace Microsoft::Console::Render;
|
|||
// - dxFontRenderData - The DirectWrite font render data for our layout
|
||||
CustomTextLayout::CustomTextLayout(gsl::not_null<DxFontRenderData*> const fontRenderData) :
|
||||
_fontRenderData{ fontRenderData },
|
||||
_formatInUse{ fontRenderData->DefaultTextFormat() },
|
||||
_fontInUse{ fontRenderData->DefaultFontFace() },
|
||||
_formatInUse{ fontRenderData->DefaultTextFormat().Get() },
|
||||
_fontInUse{ fontRenderData->DefaultFontFace().Get() },
|
||||
_numberSubstitution{},
|
||||
_readingDirection{ DWRITE_READING_DIRECTION_LEFT_TO_RIGHT },
|
||||
_runs{},
|
||||
|
@ -100,8 +100,8 @@ CATCH_RETURN()
|
|||
RETURN_HR_IF_NULL(E_INVALIDARG, columns);
|
||||
*columns = 0;
|
||||
|
||||
_formatInUse = _fontRenderData->DefaultTextFormat();
|
||||
_fontInUse = _fontRenderData->DefaultFontFace();
|
||||
_formatInUse = _fontRenderData->DefaultTextFormat().Get();
|
||||
_fontInUse = _fontRenderData->DefaultFontFace().Get();
|
||||
|
||||
RETURN_IF_FAILED(_AnalyzeTextComplexity());
|
||||
RETURN_IF_FAILED(_AnalyzeRuns());
|
||||
|
@ -139,19 +139,28 @@ try
|
|||
|
||||
DWRITE_FONT_WEIGHT weight = _fontRenderData->DefaultFontWeight();
|
||||
DWRITE_FONT_STYLE style = _fontRenderData->DefaultFontStyle();
|
||||
const DWRITE_FONT_STRETCH stretch = _fontRenderData->DefaultFontStretch();
|
||||
|
||||
if (drawingContext->useBoldFont)
|
||||
{
|
||||
// TODO: "relative" bold?
|
||||
weight = DWRITE_FONT_WEIGHT_BOLD;
|
||||
// Since we are setting the font weight according to the text attribute,
|
||||
// make sure to tell the text format to ignore the user set font weight
|
||||
_fontRenderData->InhibitUserWeight(true);
|
||||
}
|
||||
if (drawingContext->useItalicFont)
|
||||
else
|
||||
{
|
||||
_fontRenderData->InhibitUserWeight(false);
|
||||
}
|
||||
|
||||
if (drawingContext->useItalicFont || _fontRenderData->DidUserSetItalic())
|
||||
{
|
||||
style = DWRITE_FONT_STYLE_ITALIC;
|
||||
}
|
||||
|
||||
_formatInUse = _fontRenderData->TextFormatWithAttribute(weight, style);
|
||||
_fontInUse = _fontRenderData->FontFaceWithAttribute(weight, style);
|
||||
_formatInUse = _fontRenderData->TextFormatWithAttribute(weight, style, stretch).Get();
|
||||
_fontInUse = _fontRenderData->FontFaceWithAttribute(weight, style, stretch).Get();
|
||||
|
||||
RETURN_IF_FAILED(_AnalyzeTextComplexity());
|
||||
RETURN_IF_FAILED(_AnalyzeRuns());
|
||||
|
@ -394,25 +403,12 @@ CATCH_RETURN()
|
|||
std::vector<DWRITE_SHAPING_TEXT_PROPERTIES> textProps(textLength);
|
||||
std::vector<DWRITE_SHAPING_GLYPH_PROPERTIES> glyphProps(maxGlyphCount);
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26494) // Variable '...' is uninitialized. Always initialize an object (type.5).
|
||||
// None of these variables need to be initialized.
|
||||
// features/featureRangeLengths are marked _In_reads_opt_(featureRanges).
|
||||
// featureRanges is only > 0 when we also initialize all these variables.
|
||||
DWRITE_TYPOGRAPHIC_FEATURES typographicFeatures;
|
||||
const DWRITE_TYPOGRAPHIC_FEATURES* typographicFeaturesPointer;
|
||||
UINT32 fontFeatureLengths;
|
||||
#pragma warning(pop)
|
||||
UINT32 featureRanges = 0;
|
||||
|
||||
if (const auto& features = _fontRenderData->DefaultFontFeatures(); !features.empty())
|
||||
{
|
||||
typographicFeatures.features = const_cast<DWRITE_FONT_FEATURE*>(features.data());
|
||||
typographicFeatures.featureCount = gsl::narrow_cast<UINT32>(features.size());
|
||||
typographicFeaturesPointer = &typographicFeatures;
|
||||
fontFeatureLengths = textLength;
|
||||
featureRanges = 1;
|
||||
}
|
||||
// Get the features to apply to the font
|
||||
const auto& features = _fontRenderData->DefaultFontFeatures();
|
||||
#pragma warning(suppress : 26492) // Don't use const_cast to cast away const or volatile (type.3).
|
||||
DWRITE_TYPOGRAPHIC_FEATURES typographicFeatures = { const_cast<DWRITE_FONT_FEATURE*>(features.data()), gsl::narrow<uint32_t>(features.size()) };
|
||||
DWRITE_TYPOGRAPHIC_FEATURES const* typographicFeaturesPointer = &typographicFeatures;
|
||||
const uint32_t fontFeatureLengths[] = { textLength };
|
||||
|
||||
// Get the glyphs from the text, retrying if needed.
|
||||
|
||||
|
@ -432,8 +428,8 @@ CATCH_RETURN()
|
|||
_localeName.data(),
|
||||
(run.isNumberSubstituted) ? _numberSubstitution.Get() : nullptr,
|
||||
&typographicFeaturesPointer, // features
|
||||
&fontFeatureLengths,
|
||||
featureRanges,
|
||||
&fontFeatureLengths[0], // featureLengths
|
||||
1, // featureCount
|
||||
maxGlyphCount, // maxGlyphCount
|
||||
&_glyphClusters.at(textStart),
|
||||
&textProps.at(0),
|
||||
|
@ -482,8 +478,8 @@ CATCH_RETURN()
|
|||
&run.script,
|
||||
_localeName.data(),
|
||||
&typographicFeaturesPointer, // features
|
||||
&fontFeatureLengths,
|
||||
featureRanges,
|
||||
&fontFeatureLengths[0], // featureLengths
|
||||
1, // featureCount
|
||||
&_glyphAdvances.at(glyphStart),
|
||||
&_glyphOffsets.at(glyphStart));
|
||||
|
||||
|
@ -1290,7 +1286,7 @@ CATCH_RETURN();
|
|||
// newer MapCharacters to apply axes of variation to the font
|
||||
if (!FAILED(_formatInUse->QueryInterface(IID_PPV_ARGS(&format3))) && !FAILED(fallback->QueryInterface(IID_PPV_ARGS(&fallback1))))
|
||||
{
|
||||
const auto& axesVector = _fontRenderData->GetAxisVector(weight, style);
|
||||
const auto axesVector = _fontRenderData->GetAxisVector(weight, stretch, style, format3.Get());
|
||||
// Walk through and analyze the entire string
|
||||
while (textLength > 0)
|
||||
{
|
||||
|
@ -1517,7 +1513,7 @@ try
|
|||
{
|
||||
auto& run = _FetchNextRun(textLength);
|
||||
|
||||
if (run.fontFace.Get() == _fontRenderData->DefaultFontFace())
|
||||
if (run.fontFace == _fontRenderData->DefaultFontFace())
|
||||
{
|
||||
run.drawingEffect = _fontRenderData->DefaultBoxDrawingEffect();
|
||||
}
|
||||
|
|
407
src/renderer/dx/DxFontInfo.cpp
Normal file
407
src/renderer/dx/DxFontInfo.cpp
Normal file
|
@ -0,0 +1,407 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include "DxFontInfo.h"
|
||||
|
||||
#include "unicode.hpp"
|
||||
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
static constexpr std::wstring_view FALLBACK_FONT_FACES[] = { L"Consolas", L"Lucida Console", L"Courier New" };
|
||||
|
||||
using namespace Microsoft::Console::Render;
|
||||
|
||||
DxFontInfo::DxFontInfo() noexcept :
|
||||
_familyName(),
|
||||
_weight(DWRITE_FONT_WEIGHT_NORMAL),
|
||||
_style(DWRITE_FONT_STYLE_NORMAL),
|
||||
_stretch(DWRITE_FONT_STRETCH_NORMAL),
|
||||
_didFallback(false)
|
||||
{
|
||||
}
|
||||
|
||||
DxFontInfo::DxFontInfo(std::wstring_view familyName,
|
||||
unsigned int weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch) :
|
||||
DxFontInfo(familyName, static_cast<DWRITE_FONT_WEIGHT>(weight), style, stretch)
|
||||
{
|
||||
}
|
||||
|
||||
DxFontInfo::DxFontInfo(std::wstring_view familyName,
|
||||
DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch) :
|
||||
_familyName(familyName),
|
||||
_weight(weight),
|
||||
_style(style),
|
||||
_stretch(stretch),
|
||||
_didFallback(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool DxFontInfo::operator==(const DxFontInfo& other) const noexcept
|
||||
{
|
||||
return (_familyName == other._familyName &&
|
||||
_weight == other._weight &&
|
||||
_style == other._style &&
|
||||
_stretch == other._stretch &&
|
||||
_didFallback == other._didFallback);
|
||||
}
|
||||
|
||||
std::wstring_view DxFontInfo::GetFamilyName() const noexcept
|
||||
{
|
||||
return _familyName;
|
||||
}
|
||||
|
||||
void DxFontInfo::SetFamilyName(const std::wstring_view familyName)
|
||||
{
|
||||
_familyName = familyName;
|
||||
}
|
||||
|
||||
DWRITE_FONT_WEIGHT DxFontInfo::GetWeight() const noexcept
|
||||
{
|
||||
return _weight;
|
||||
}
|
||||
|
||||
void DxFontInfo::SetWeight(const DWRITE_FONT_WEIGHT weight) noexcept
|
||||
{
|
||||
_weight = weight;
|
||||
}
|
||||
|
||||
DWRITE_FONT_STYLE DxFontInfo::GetStyle() const noexcept
|
||||
{
|
||||
return _style;
|
||||
}
|
||||
|
||||
void DxFontInfo::SetStyle(const DWRITE_FONT_STYLE style) noexcept
|
||||
{
|
||||
_style = style;
|
||||
}
|
||||
|
||||
DWRITE_FONT_STRETCH DxFontInfo::GetStretch() const noexcept
|
||||
{
|
||||
return _stretch;
|
||||
}
|
||||
|
||||
void DxFontInfo::SetStretch(const DWRITE_FONT_STRETCH stretch) noexcept
|
||||
{
|
||||
_stretch = stretch;
|
||||
}
|
||||
|
||||
bool DxFontInfo::GetFallback() const noexcept
|
||||
{
|
||||
return _didFallback;
|
||||
}
|
||||
|
||||
IDWriteFontCollection* DxFontInfo::GetNearbyCollection() const noexcept
|
||||
{
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
void DxFontInfo::SetFromEngine(const std::wstring_view familyName,
|
||||
const DWRITE_FONT_WEIGHT weight,
|
||||
const DWRITE_FONT_STYLE style,
|
||||
const DWRITE_FONT_STRETCH stretch)
|
||||
{
|
||||
_familyName = familyName;
|
||||
_weight = weight;
|
||||
_style = style;
|
||||
_stretch = stretch;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Attempts to locate the font given, but then begins falling back if we cannot find it.
|
||||
// - We'll try to fall back to Consolas with the given weight/stretch/style first,
|
||||
// then try Consolas again with normal weight/stretch/style,
|
||||
// and if nothing works, then we'll throw an error.
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// - localeName - Locale to search for appropriate fonts
|
||||
// Return Value:
|
||||
// - Smart pointer holding interface reference for queryable font data.
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::ResolveFontFaceWithFallback(gsl::not_null<IDWriteFactory1*> dwriteFactory,
|
||||
std::wstring& localeName)
|
||||
{
|
||||
// First attempt to find exactly what the user asked for.
|
||||
_didFallback = false;
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace1> face{ nullptr };
|
||||
|
||||
// GH#10211 - wrap this all up in a try/catch. If the nearby fonts are
|
||||
// corrupted, then we don't want to throw out of this top half of this
|
||||
// method. We still want to fall back to a font that's reasonable, below.
|
||||
try
|
||||
{
|
||||
face = _FindFontFace(dwriteFactory, localeName, true);
|
||||
|
||||
if (!face)
|
||||
{
|
||||
// If we missed, try looking a little more by trimming the last word off the requested family name a few times.
|
||||
// Quite often, folks are specifying weights or something in the familyName and it causes failed resolution and
|
||||
// an unexpected error dialog. We theoretically could detect the weight words and convert them, but this
|
||||
// is the quick fix for the majority scenario.
|
||||
// The long/full fix is backlogged to GH#9744
|
||||
// Also this doesn't count as a fallback because we don't want to annoy folks with the warning dialog over
|
||||
// this resolution.
|
||||
while (!face && !_familyName.empty())
|
||||
{
|
||||
const auto lastSpace = _familyName.find_last_of(UNICODE_SPACE);
|
||||
|
||||
// value is unsigned and npos will be greater than size.
|
||||
// if we didn't find anything to trim, leave.
|
||||
if (lastSpace >= _familyName.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// trim string down to just before the found space
|
||||
// (space found at 6... trim from 0 for 6 length will give us 0-5 as the new string)
|
||||
_familyName = _familyName.substr(0, lastSpace);
|
||||
|
||||
// Try to find it with the shortened family name
|
||||
face = _FindFontFace(dwriteFactory, localeName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// Alright, if our quick shot at trimming didn't work either...
|
||||
// move onto looking up a font from our hardcoded list of fonts
|
||||
// that should really always be available.
|
||||
if (!face)
|
||||
{
|
||||
for (const auto fallbackFace : FALLBACK_FONT_FACES)
|
||||
{
|
||||
_familyName = fallbackFace;
|
||||
// With these fonts, don't attempt the nearby lookup. We're looking
|
||||
// for system fonts only. If one of the nearby fonts is causing us
|
||||
// problems (like in GH#10211), then we don't want to go anywhere
|
||||
|
||||
// near it in this part.
|
||||
face = _FindFontFace(dwriteFactory, localeName, false);
|
||||
|
||||
if (face)
|
||||
{
|
||||
_didFallback = true;
|
||||
break;
|
||||
}
|
||||
|
||||
_familyName = fallbackFace;
|
||||
_weight = DWRITE_FONT_WEIGHT_NORMAL;
|
||||
_stretch = DWRITE_FONT_STRETCH_NORMAL;
|
||||
_style = DWRITE_FONT_STYLE_NORMAL;
|
||||
face = _FindFontFace(dwriteFactory, localeName, false);
|
||||
|
||||
if (face)
|
||||
{
|
||||
_didFallback = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
THROW_HR_IF_NULL(E_FAIL, face);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Locates a suitable font face from the given information
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// - localeName - Locale to search for appropriate fonts
|
||||
// Return Value:
|
||||
// - Smart pointer holding interface reference for queryable font data.
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontInfo::_FindFontFace(gsl::not_null<IDWriteFactory1*> dwriteFactory, std::wstring& localeName, const bool withNearbyLookup)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFontCollection> fontCollection;
|
||||
THROW_IF_FAILED(dwriteFactory->GetSystemFontCollection(&fontCollection, false));
|
||||
|
||||
UINT32 familyIndex;
|
||||
BOOL familyExists;
|
||||
THROW_IF_FAILED(fontCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));
|
||||
|
||||
// If the system collection missed, try the files sitting next to our binary.
|
||||
if (withNearbyLookup && !familyExists)
|
||||
{
|
||||
// May be null on OS below Windows 10. If null, just skip the attempt.
|
||||
if (const auto nearbyCollection = _NearbyCollection(dwriteFactory))
|
||||
{
|
||||
THROW_IF_FAILED(nearbyCollection->FindFamilyName(_familyName.data(), &familyIndex, &familyExists));
|
||||
fontCollection = nearbyCollection;
|
||||
}
|
||||
}
|
||||
|
||||
if (familyExists)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFamily> fontFamily;
|
||||
THROW_IF_FAILED(fontCollection->GetFontFamily(familyIndex, &fontFamily));
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFont> font;
|
||||
THROW_IF_FAILED(fontFamily->GetFirstMatchingFont(GetWeight(), GetStretch(), GetStyle(), &font));
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace> fontFace0;
|
||||
THROW_IF_FAILED(font->CreateFontFace(&fontFace0));
|
||||
|
||||
THROW_IF_FAILED(fontFace0.As(&fontFace));
|
||||
|
||||
// Retrieve metrics in case the font we created was different than what was requested.
|
||||
_weight = font->GetWeight();
|
||||
_stretch = font->GetStretch();
|
||||
_style = font->GetStyle();
|
||||
|
||||
// Dig the family name out at the end to return it.
|
||||
_familyName = _GetFontFamilyName(fontFamily.Get(), localeName);
|
||||
}
|
||||
|
||||
return fontFace;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the font family name out of the given object in the given locale.
|
||||
// - If we can't find a valid name for the given locale, we'll fallback and report it back.
|
||||
// Arguments:
|
||||
// - fontFamily - DirectWrite font family object
|
||||
// - localeName - The locale in which the name should be retrieved.
|
||||
// - If fallback occurred, this is updated to what we retrieved instead.
|
||||
// Return Value:
|
||||
// - Localized string name of the font family
|
||||
[[nodiscard]] std::wstring DxFontInfo::_GetFontFamilyName(gsl::not_null<IDWriteFontFamily*> const fontFamily,
|
||||
std::wstring& localeName)
|
||||
{
|
||||
// See: https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nn-dwrite-idwritefontcollection
|
||||
Microsoft::WRL::ComPtr<IDWriteLocalizedStrings> familyNames;
|
||||
THROW_IF_FAILED(fontFamily->GetFamilyNames(&familyNames));
|
||||
|
||||
// First we have to find the right family name for the locale. We're going to bias toward what the caller
|
||||
// requested, but fallback if we need to and reply with the locale we ended up choosing.
|
||||
UINT32 index = 0;
|
||||
BOOL exists = false;
|
||||
|
||||
// This returns S_OK whether or not it finds a locale name. Check exists field instead.
|
||||
// If it returns an error, it's a real problem, not an absence of this locale name.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-findlocalename
|
||||
THROW_IF_FAILED(familyNames->FindLocaleName(localeName.data(), &index, &exists));
|
||||
|
||||
// If we tried and it still doesn't exist, try with the fallback locale.
|
||||
if (!exists)
|
||||
{
|
||||
localeName = L"en-us";
|
||||
THROW_IF_FAILED(familyNames->FindLocaleName(localeName.data(), &index, &exists));
|
||||
}
|
||||
|
||||
// If it still doesn't exist, we're going to try index 0.
|
||||
if (!exists)
|
||||
{
|
||||
index = 0;
|
||||
|
||||
// Get the locale name out so at least the caller knows what locale this name goes with.
|
||||
UINT32 length = 0;
|
||||
THROW_IF_FAILED(familyNames->GetLocaleNameLength(index, &length));
|
||||
localeName.resize(length);
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-getlocalenamelength
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-getlocalename
|
||||
// GetLocaleNameLength does not include space for null terminator, but GetLocaleName needs it so add one.
|
||||
THROW_IF_FAILED(familyNames->GetLocaleName(index, localeName.data(), length + 1));
|
||||
}
|
||||
|
||||
// OK, now that we've decided which family name and the locale that it's in... let's go get it.
|
||||
UINT32 length = 0;
|
||||
THROW_IF_FAILED(familyNames->GetStringLength(index, &length));
|
||||
|
||||
// Make our output buffer and resize it so it is allocated.
|
||||
std::wstring retVal;
|
||||
retVal.resize(length);
|
||||
|
||||
// FINALLY, go fetch the string name.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-getstringlength
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-getstring
|
||||
// Once again, GetStringLength is without the null, but GetString needs the null. So add one.
|
||||
THROW_IF_FAILED(familyNames->GetString(index, retVal.data(), length + 1));
|
||||
|
||||
// and return it.
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Creates a DirectWrite font collection of font files that are sitting next to the running
|
||||
// binary (in the same directory as the EXE).
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// Return Value:
|
||||
// - DirectWrite font collection. May be null if one cannot be created.
|
||||
[[nodiscard]] IDWriteFontCollection* DxFontInfo::_NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory)
|
||||
{
|
||||
if (_nearbyCollection)
|
||||
{
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
// The convenience interfaces for loading fonts from files
|
||||
// are only available on Windows 10+.
|
||||
::Microsoft::WRL::ComPtr<IDWriteFactory6> factory6;
|
||||
if (FAILED(dwriteFactory->QueryInterface<IDWriteFactory6>(&factory6)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> systemFontCollection;
|
||||
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, &systemFontCollection, 0));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> systemFontSet;
|
||||
THROW_IF_FAILED(systemFontCollection->GetFontSet(&systemFontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSetBuilder2> fontSetBuilder2;
|
||||
THROW_IF_FAILED(factory6->CreateFontSetBuilder(&fontSetBuilder2));
|
||||
|
||||
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.Get()));
|
||||
|
||||
// Magic static so we only attempt to grovel the hard disk once no matter how many instances
|
||||
// of the font collection itself we require.
|
||||
static const auto knownPaths = s_GetNearbyFonts();
|
||||
for (auto& p : knownPaths)
|
||||
{
|
||||
fontSetBuilder2->AddFontFile(p.c_str());
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> fontSet;
|
||||
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(&fontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> fontCollection;
|
||||
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.Get(), &fontCollection));
|
||||
|
||||
_nearbyCollection = fontCollection;
|
||||
return _nearbyCollection.Get();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Digs through the directory that the current executable is running within to find
|
||||
// any TTF files sitting next to it.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - Iterable collection of filesystem paths, one per font file that was found
|
||||
[[nodiscard]] std::vector<std::filesystem::path> DxFontInfo::s_GetNearbyFonts()
|
||||
{
|
||||
std::vector<std::filesystem::path> paths;
|
||||
|
||||
// Find the directory we're running from then enumerate all the TTF files
|
||||
// sitting next to us.
|
||||
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
const auto folder{ module.parent_path() };
|
||||
|
||||
for (const auto& p : std::filesystem::directory_iterator(folder))
|
||||
{
|
||||
if (til::ends_with(p.path().native(), L".ttf"))
|
||||
{
|
||||
paths.push_back(p.path());
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
83
src/renderer/dx/DxFontInfo.h
Normal file
83
src/renderer/dx/DxFontInfo.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dwrite.h>
|
||||
#include <dwrite_1.h>
|
||||
#include <dwrite_2.h>
|
||||
#include <dwrite_3.h>
|
||||
|
||||
namespace Microsoft::Console::Render
|
||||
{
|
||||
class DxFontInfo
|
||||
{
|
||||
public:
|
||||
DxFontInfo() noexcept;
|
||||
|
||||
DxFontInfo(std::wstring_view familyName,
|
||||
unsigned int weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
DxFontInfo(std::wstring_view familyName,
|
||||
DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
bool operator==(const DxFontInfo& other) const noexcept;
|
||||
|
||||
std::wstring_view GetFamilyName() const noexcept;
|
||||
void SetFamilyName(const std::wstring_view familyName);
|
||||
|
||||
DWRITE_FONT_WEIGHT GetWeight() const noexcept;
|
||||
void SetWeight(const DWRITE_FONT_WEIGHT weight) noexcept;
|
||||
|
||||
DWRITE_FONT_STYLE GetStyle() const noexcept;
|
||||
void SetStyle(const DWRITE_FONT_STYLE style) noexcept;
|
||||
|
||||
DWRITE_FONT_STRETCH GetStretch() const noexcept;
|
||||
void SetStretch(const DWRITE_FONT_STRETCH stretch) noexcept;
|
||||
|
||||
bool GetFallback() const noexcept;
|
||||
|
||||
IDWriteFontCollection* GetNearbyCollection() const noexcept;
|
||||
|
||||
void SetFromEngine(const std::wstring_view familyName,
|
||||
const DWRITE_FONT_WEIGHT weight,
|
||||
const DWRITE_FONT_STYLE style,
|
||||
const DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> ResolveFontFaceWithFallback(gsl::not_null<IDWriteFactory1*> dwriteFactory,
|
||||
std::wstring& localeName);
|
||||
|
||||
private:
|
||||
[[nodiscard]] ::Microsoft::WRL::ComPtr<IDWriteFontFace1> _FindFontFace(gsl::not_null<IDWriteFactory1*> dwriteFactory,
|
||||
std::wstring& localeName,
|
||||
const bool withNearbyLookup);
|
||||
|
||||
[[nodiscard]] std::wstring _GetFontFamilyName(gsl::not_null<IDWriteFontFamily*> const fontFamily,
|
||||
std::wstring& localeName);
|
||||
|
||||
[[nodiscard]] IDWriteFontCollection* _NearbyCollection(gsl::not_null<IDWriteFactory1*> dwriteFactory);
|
||||
|
||||
[[nodiscard]] static std::vector<std::filesystem::path> s_GetNearbyFonts();
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection> _nearbyCollection;
|
||||
|
||||
// The font name we should be looking for
|
||||
std::wstring _familyName;
|
||||
|
||||
// The weight (bold, light, etc.)
|
||||
DWRITE_FONT_WEIGHT _weight;
|
||||
|
||||
// Normal, italic, etc.
|
||||
DWRITE_FONT_STYLE _style;
|
||||
|
||||
// The stretch of the font is the spacing between each letter
|
||||
DWRITE_FONT_STRETCH _stretch;
|
||||
|
||||
// Indicates whether we couldn't match the user request and had to choose from a hardcoded default list.
|
||||
bool _didFallback;
|
||||
};
|
||||
}
|
|
@ -10,14 +10,16 @@
|
|||
#include <VersionHelpers.h>
|
||||
|
||||
static constexpr float POINTS_PER_INCH = 72.0f;
|
||||
static constexpr const wchar_t* FALLBACK_FONT_FACES[] = { L"Consolas", L"Lucida Console", L"Courier New" };
|
||||
static constexpr wchar_t FALLBACK_LOCALE[]{ L"en-us" };
|
||||
static constexpr std::wstring_view FALLBACK_FONT_FACES[] = { L"Consolas", L"Lucida Console", L"Courier New" };
|
||||
static constexpr std::wstring_view FALLBACK_LOCALE = L"en-us";
|
||||
static constexpr size_t TAG_LENGTH = 4;
|
||||
|
||||
using namespace Microsoft::Console::Render;
|
||||
|
||||
DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwriteFactory) noexcept :
|
||||
_dwriteFactory(dwriteFactory),
|
||||
_fontSize{},
|
||||
_glyphCell{},
|
||||
_lineMetrics{},
|
||||
_lineSpacing{}
|
||||
{
|
||||
|
@ -47,46 +49,49 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwr
|
|||
return _systemFontFallback;
|
||||
}
|
||||
|
||||
void DxFontRenderData::_RefreshUserLocaleName()
|
||||
[[nodiscard]] std::wstring DxFontRenderData::UserLocaleName()
|
||||
{
|
||||
std::array<wchar_t, LOCALE_NAME_MAX_LENGTH> buffer;
|
||||
const wchar_t* localeName = buffer.data();
|
||||
auto length = GetUserDefaultLocaleName(buffer.data(), gsl::narrow_cast<int>(buffer.size()));
|
||||
|
||||
if (length <= 0)
|
||||
if (_userLocaleName.empty())
|
||||
{
|
||||
localeName = &FALLBACK_LOCALE[0];
|
||||
length = sizeof(FALLBACK_LOCALE);
|
||||
std::array<wchar_t, LOCALE_NAME_MAX_LENGTH> localeName;
|
||||
|
||||
const auto returnCode = GetUserDefaultLocaleName(localeName.data(), gsl::narrow<int>(localeName.size()));
|
||||
if (returnCode)
|
||||
{
|
||||
_userLocaleName = { localeName.data() };
|
||||
}
|
||||
else
|
||||
{
|
||||
_userLocaleName = { FALLBACK_LOCALE.data(), FALLBACK_LOCALE.size() };
|
||||
}
|
||||
}
|
||||
|
||||
// length is including the trailing null byte.
|
||||
// See GetUserDefaultLocaleName()'s docs.
|
||||
_userLocaleName = wil::make_process_heap_string_nothrow(localeName, length - 1);
|
||||
return _userLocaleName;
|
||||
}
|
||||
|
||||
[[nodiscard]] til::size DxFontRenderData::GlyphCell() const noexcept
|
||||
[[nodiscard]] til::size DxFontRenderData::GlyphCell() noexcept
|
||||
{
|
||||
return _glyphCell;
|
||||
}
|
||||
|
||||
[[nodiscard]] DxFontRenderData::LineMetrics DxFontRenderData::GetLineMetrics() const noexcept
|
||||
[[nodiscard]] DxFontRenderData::LineMetrics DxFontRenderData::GetLineMetrics() noexcept
|
||||
{
|
||||
return _lineMetrics;
|
||||
}
|
||||
|
||||
[[nodiscard]] DWRITE_FONT_WEIGHT DxFontRenderData::DefaultFontWeight() const noexcept
|
||||
[[nodiscard]] DWRITE_FONT_WEIGHT DxFontRenderData::DefaultFontWeight() noexcept
|
||||
{
|
||||
return _userFontWeight;
|
||||
return _defaultFontInfo.GetWeight();
|
||||
}
|
||||
|
||||
[[nodiscard]] DWRITE_FONT_STYLE DxFontRenderData::DefaultFontStyle() noexcept
|
||||
{
|
||||
return DWRITE_FONT_STYLE_NORMAL;
|
||||
return _defaultFontInfo.GetStyle();
|
||||
}
|
||||
|
||||
[[nodiscard]] DWRITE_FONT_STRETCH DxFontRenderData::DefaultFontStretch() noexcept
|
||||
{
|
||||
return DWRITE_FONT_STRETCH_NORMAL;
|
||||
return _defaultFontInfo.GetStretch();
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<DWRITE_FONT_FEATURE>& DxFontRenderData::DefaultFontFeatures() const noexcept
|
||||
|
@ -94,40 +99,81 @@ void DxFontRenderData::_RefreshUserLocaleName()
|
|||
return _featureVector;
|
||||
}
|
||||
|
||||
[[nodiscard]] IDWriteTextFormat* DxFontRenderData::DefaultTextFormat() const noexcept
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::DefaultTextFormat()
|
||||
{
|
||||
return _textFormats[0][0].Get();
|
||||
return TextFormatWithAttribute(_defaultFontInfo.GetWeight(), _defaultFontInfo.GetStyle(), _defaultFontInfo.GetStretch());
|
||||
}
|
||||
|
||||
[[nodiscard]] IDWriteFontFace1* DxFontRenderData::DefaultFontFace() const noexcept
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontRenderData::DefaultFontFace()
|
||||
{
|
||||
return _fontFaces[0][0].Get();
|
||||
return FontFaceWithAttribute(_defaultFontInfo.GetWeight(), _defaultFontInfo.GetStyle(), _defaultFontInfo.GetStretch());
|
||||
}
|
||||
|
||||
[[nodiscard]] IBoxDrawingEffect* DxFontRenderData::DefaultBoxDrawingEffect()
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IBoxDrawingEffect> DxFontRenderData::DefaultBoxDrawingEffect()
|
||||
{
|
||||
if (!_boxDrawingEffect)
|
||||
{
|
||||
// Calculate and cache the box effect for the base font. Scale is 1.0f because the base font is exactly the scale we want already.
|
||||
THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat(), _glyphCell.width(), DefaultFontFace(), 1.0f, &_boxDrawingEffect));
|
||||
THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat().Get(), _glyphCell.width(), DefaultFontFace().Get(), 1.0f, &_boxDrawingEffect));
|
||||
}
|
||||
|
||||
return _boxDrawingEffect.Get();
|
||||
return _boxDrawingEffect;
|
||||
}
|
||||
|
||||
[[nodiscard]] IDWriteTextFormat* DxFontRenderData::TextFormatWithAttribute(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::TextFormatWithAttribute(DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch)
|
||||
{
|
||||
return _textFormats[style != DWRITE_FONT_STYLE_NORMAL][weight != _userFontWeight].Get();
|
||||
const auto textFormatIt = _textFormatMap.find(_ToMapKey(weight, style, stretch));
|
||||
if (textFormatIt == _textFormatMap.end())
|
||||
{
|
||||
DxFontInfo fontInfo = _defaultFontInfo;
|
||||
fontInfo.SetWeight(weight);
|
||||
fontInfo.SetStyle(style);
|
||||
fontInfo.SetStretch(stretch);
|
||||
|
||||
// Create the font with the fractional pixel height size.
|
||||
// It should have an integer pixel width by our math.
|
||||
// Then below, apply the line spacing to the format to position the floating point pixel height characters
|
||||
// into a cell that has an integer pixel height leaving some padding above/below as necessary to round them out.
|
||||
std::wstring localeName = UserLocaleName();
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> textFormat;
|
||||
THROW_IF_FAILED(_BuildTextFormat(fontInfo, localeName).As(&textFormat));
|
||||
THROW_IF_FAILED(textFormat->SetLineSpacing(_lineSpacing.method, _lineSpacing.height, _lineSpacing.baseline));
|
||||
THROW_IF_FAILED(textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR));
|
||||
THROW_IF_FAILED(textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP));
|
||||
|
||||
_textFormatMap.emplace(_ToMapKey(weight, style, stretch), textFormat);
|
||||
return textFormat;
|
||||
}
|
||||
else
|
||||
{
|
||||
return textFormatIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] IDWriteFontFace1* DxFontRenderData::FontFaceWithAttribute(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DxFontRenderData::FontFaceWithAttribute(DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch)
|
||||
{
|
||||
return _fontFaces[style != DWRITE_FONT_STYLE_NORMAL][weight != _userFontWeight].Get();
|
||||
}
|
||||
const auto fontFaceIt = _fontFaceMap.find(_ToMapKey(weight, style, stretch));
|
||||
if (fontFaceIt == _fontFaceMap.end())
|
||||
{
|
||||
DxFontInfo fontInfo = _defaultFontInfo;
|
||||
fontInfo.SetWeight(weight);
|
||||
fontInfo.SetStyle(style);
|
||||
fontInfo.SetStretch(stretch);
|
||||
|
||||
const std::vector<DWRITE_FONT_AXIS_VALUE>& DxFontRenderData::GetAxisVector(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept
|
||||
{
|
||||
return _textFormatAxes[style != DWRITE_FONT_STYLE_NORMAL][weight != _userFontWeight];
|
||||
std::wstring fontLocaleName = UserLocaleName();
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace = fontInfo.ResolveFontFaceWithFallback(_dwriteFactory.Get(), fontLocaleName);
|
||||
|
||||
_fontFaceMap.emplace(_ToMapKey(weight, style, stretch), fontFace);
|
||||
return fontFace;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fontFaceIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -139,147 +185,29 @@ const std::vector<DWRITE_FONT_AXIS_VALUE>& DxFontRenderData::GetAxisVector(DWRIT
|
|||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxFontRenderData::UpdateFont(const FontInfoDesired& desired, FontInfo& actual, const int dpi, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
|
||||
try
|
||||
{
|
||||
std::vector<DWRITE_FONT_FEATURE> fontFeatures;
|
||||
if (!features.empty())
|
||||
try
|
||||
{
|
||||
fontFeatures.reserve(features.size() + 3);
|
||||
_userLocaleName.clear();
|
||||
_textFormatMap.clear();
|
||||
_fontFaceMap.clear();
|
||||
_boxDrawingEffect.Reset();
|
||||
|
||||
// All of these features are enabled by default by DirectWrite.
|
||||
// If you want to (and can) peek into the source of DirectWrite
|
||||
// you can look for the "GenericDefaultGsubFeatures" and "GenericDefaultGposFeatures" arrays.
|
||||
// Gsub is for GetGlyphs() and Gpos for GetGlyphPlacements().
|
||||
//
|
||||
// GH#10774: Apparently specifying all of the features is just redundant.
|
||||
fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES, 1 });
|
||||
fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES, 1 });
|
||||
fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES, 1 });
|
||||
// Initialize the default font info and build everything from here.
|
||||
_defaultFontInfo = DxFontInfo(desired.GetFaceName(),
|
||||
desired.GetWeight(),
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL);
|
||||
|
||||
for (const auto& p : features)
|
||||
{
|
||||
if (p.first.size() == 4)
|
||||
{
|
||||
const auto s = p.first.data();
|
||||
switch (const auto tag = DWRITE_MAKE_FONT_FEATURE_TAG(s[0], s[1], s[2], s[3]))
|
||||
{
|
||||
case DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES:
|
||||
fontFeatures[0].parameter = p.second;
|
||||
break;
|
||||
case DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES:
|
||||
fontFeatures[1].parameter = p.second;
|
||||
break;
|
||||
case DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES:
|
||||
fontFeatures[2].parameter = p.second;
|
||||
break;
|
||||
default:
|
||||
fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ tag, p.second });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> fontAxisValues;
|
||||
if (!axes.empty())
|
||||
{
|
||||
fontAxisValues.reserve(axes.size() + 3);
|
||||
|
||||
// Just a few lines below we configure IDWriteTextFormat3 instances with these font axes.
|
||||
// We need at least all 3 of these axes below, in order to ensure that if we get a request for an italic
|
||||
// text format, we can supply an italic one, no matter what font axes the user set (or didn't set).
|
||||
fontAxisValues.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_WEIGHT, -1.0f });
|
||||
fontAxisValues.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_ITALIC, -1.0f });
|
||||
fontAxisValues.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_SLANT, -1.0f });
|
||||
|
||||
for (const auto& p : axes)
|
||||
{
|
||||
if (p.first.size() == 4)
|
||||
{
|
||||
const auto s = p.first.data();
|
||||
switch (const auto tag = DWRITE_MAKE_FONT_AXIS_TAG(s[0], s[1], s[2], s[3]))
|
||||
{
|
||||
case DWRITE_FONT_AXIS_TAG_WEIGHT:
|
||||
fontAxisValues[0].value = p.second;
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_ITALIC:
|
||||
fontAxisValues[1].value = p.second;
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_SLANT:
|
||||
fontAxisValues[2].value = p.second;
|
||||
break;
|
||||
default:
|
||||
fontAxisValues.emplace_back(DWRITE_FONT_AXIS_VALUE{ tag, p.second });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_RefreshUserLocaleName();
|
||||
_BuildFontRenderData(desired, actual, dpi);
|
||||
_featureVector = std::move(fontFeatures);
|
||||
_userFontWeight = static_cast<DWRITE_FONT_WEIGHT>(actual.GetWeight());
|
||||
_boxDrawingEffect.Reset();
|
||||
|
||||
{
|
||||
// Just a few lines above we hardcode indices 0/1/2 in fontAxisValues to the weight/italic/slant axes.
|
||||
// If they're -1.0f they haven't been set by the user and must be filled by us.
|
||||
// When we call SetFontAxisValues() we basically override (disable) DirectWrite's internal font axes,
|
||||
// and if either of the 3 aren't set we'd make it impossible for the user to see bold/italic text.
|
||||
#pragma warning(suppress : 26494) // Variable 'standardAxes' is uninitialized. Always initialize an object (type.5).
|
||||
std::array<DWRITE_FONT_AXIS_VALUE, 3> standardAxes;
|
||||
|
||||
if (!fontAxisValues.empty())
|
||||
{
|
||||
Expects(fontAxisValues.size() >= standardAxes.size());
|
||||
memcpy(standardAxes.data(), fontAxisValues.data(), sizeof(standardAxes));
|
||||
}
|
||||
|
||||
for (auto italic = 0; italic < 2; ++italic)
|
||||
{
|
||||
for (auto bold = 0; bold < 2; ++bold)
|
||||
{
|
||||
const auto fontWeight = bold ? DWRITE_FONT_WEIGHT_BOLD : _userFontWeight;
|
||||
const auto fontStyle = italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
|
||||
auto& textFormat = _textFormats[italic][bold];
|
||||
|
||||
// If the given face name couldn't be found this will call _NearbyCollection at some point.
|
||||
// Thanks to that we can use _nearbyFontCollection.Get() below to get the font collection for our textFormat as well.
|
||||
const auto font = _ResolveFontWithFallback(actual.GetFaceName(), fontWeight, fontStyle);
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace> face;
|
||||
THROW_IF_FAILED(font->CreateFontFace(&face));
|
||||
THROW_IF_FAILED(face.As(&_fontFaces[italic][bold]));
|
||||
|
||||
THROW_IF_FAILED(_dwriteFactory->CreateTextFormat(actual.GetFaceName().c_str(), _nearbyFontCollection.Get(), font->GetWeight(), font->GetStyle(), DWRITE_FONT_STRETCH_NORMAL, _fontSize, _userLocaleName.get(), &textFormat));
|
||||
THROW_IF_FAILED(textFormat->SetLineSpacing(_lineSpacing.method, _lineSpacing.height, _lineSpacing.baseline));
|
||||
THROW_IF_FAILED(textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR));
|
||||
THROW_IF_FAILED(textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP));
|
||||
|
||||
if (!fontAxisValues.empty())
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat3> textFormat3;
|
||||
if (SUCCEEDED(textFormat.As(&textFormat3)))
|
||||
{
|
||||
// The wght axis defaults to the font weight.
|
||||
fontAxisValues[0].value = bold || standardAxes[0].value == -1.0f ? static_cast<float>(fontWeight) : standardAxes[0].value;
|
||||
// The ital axis defaults to 1 if this is italic and 0 otherwise.
|
||||
fontAxisValues[1].value = italic ? 1.0f : (standardAxes[1].value == -1.0f ? 0.0f : standardAxes[1].value);
|
||||
// The slnt axis defaults to -12 if this is italic and 0 otherwise.
|
||||
fontAxisValues[2].value = italic ? -12.0f : (standardAxes[2].value == -1.0f ? 0.0f : standardAxes[2].value);
|
||||
|
||||
THROW_IF_FAILED(textFormat3->SetFontAxisValues(fontAxisValues.data(), gsl::narrow_cast<UINT32>(fontAxisValues.size())));
|
||||
_textFormatAxes[italic][bold] = fontAxisValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_SetFeatures(features);
|
||||
_SetAxes(axes);
|
||||
|
||||
_BuildFontRenderData(desired, actual, dpi);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - Calculates the box drawing scale/translate matrix values to fit a box glyph into the cell as perfectly as possible.
|
||||
|
@ -291,7 +219,7 @@ CATCH_RETURN()
|
|||
// - effect - Receives the effect to apply to box drawing characters. If no effect is received, special treatment isn't required.
|
||||
// Return Value:
|
||||
// - S_OK, GSL/WIL errors, DirectWrite errors, or math errors.
|
||||
[[nodiscard]] HRESULT DxFontRenderData::s_CalculateBoxEffect(IDWriteTextFormat* format, size_t widthPixels, IDWriteFontFace1* face, float fontScale, IBoxDrawingEffect** effect) noexcept
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE DxFontRenderData::s_CalculateBoxEffect(IDWriteTextFormat* format, size_t widthPixels, IDWriteFontFace1* face, float fontScale, IBoxDrawingEffect** effect) noexcept
|
||||
try
|
||||
{
|
||||
// Check for bad in parameters.
|
||||
|
@ -526,14 +454,247 @@ CATCH_RETURN()
|
|||
// - Returns whether the user set or updated any of the font features to be applied
|
||||
bool DxFontRenderData::DidUserSetFeatures() const noexcept
|
||||
{
|
||||
return !_featureVector.empty();
|
||||
return _didUserSetFeatures;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Returns whether the user set or updated any of the font axes to be applied
|
||||
bool DxFontRenderData::DidUserSetAxes() const noexcept
|
||||
{
|
||||
return !_textFormatAxes[0][0].empty();
|
||||
return _didUserSetAxes;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Function called to inform us whether to use the user set weight
|
||||
// in the font axes
|
||||
// - Called by CustomTextLayout, when the text attribute is bold we should
|
||||
// ignore the user set weight, otherwise setting the bold font axis
|
||||
// breaks the bold font attribute
|
||||
// Arguments:
|
||||
// - inhibitUserWeight: boolean that tells us if we should use the user set weight
|
||||
// in the font axes
|
||||
void DxFontRenderData::InhibitUserWeight(bool inhibitUserWeight) noexcept
|
||||
{
|
||||
_inhibitUserWeight = inhibitUserWeight;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Returns whether the set italic in the font axes
|
||||
// Return Value:
|
||||
// - True if the user set the italic axis to 1,
|
||||
// false if the italic axis is not present or the italic axis is set to 0
|
||||
bool DxFontRenderData::DidUserSetItalic() const noexcept
|
||||
{
|
||||
return _didUserSetItalic;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates our internal map of font features with the given features
|
||||
// - NOTE TO CALLER: Make sure to call _BuildFontRenderData after calling this for the feature changes
|
||||
// to take place
|
||||
// Arguments:
|
||||
// - features - the features to update our map with
|
||||
void DxFontRenderData::_SetFeatures(const std::unordered_map<std::wstring_view, uint32_t>& features)
|
||||
{
|
||||
// Populate the feature map with the standard list first
|
||||
std::unordered_map<DWRITE_FONT_FEATURE_TAG, uint32_t> featureMap{
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('c', 'a', 'l', 't'), 1 }, // Contextual Alternates
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('l', 'i', 'g', 'a'), 1 }, // Standard Ligatures
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('c', 'l', 'i', 'g'), 1 }, // Contextual Ligatures
|
||||
{ DWRITE_MAKE_FONT_FEATURE_TAG('k', 'e', 'r', 'n'), 1 } // Kerning
|
||||
};
|
||||
|
||||
// Update our feature map with the provided features
|
||||
if (!features.empty())
|
||||
{
|
||||
for (const auto [tag, param] : features)
|
||||
{
|
||||
if (tag.length() == TAG_LENGTH)
|
||||
{
|
||||
featureMap.insert_or_assign(DWRITE_MAKE_FONT_FEATURE_TAG(til::at(tag, 0), til::at(tag, 1), til::at(tag, 2), til::at(tag, 3)), param);
|
||||
}
|
||||
}
|
||||
_didUserSetFeatures = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_didUserSetFeatures = false;
|
||||
}
|
||||
|
||||
// Convert the data to DWRITE_FONT_FEATURE and store it in a vector for CustomTextLayout
|
||||
_featureVector.clear();
|
||||
for (const auto [tag, param] : featureMap)
|
||||
{
|
||||
_featureVector.push_back(DWRITE_FONT_FEATURE{ tag, param });
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates our internal map of font axes with the given axes
|
||||
// - NOTE TO CALLER: Make sure to call _BuildFontRenderData after calling this for the axes changes
|
||||
// to take place
|
||||
// Arguments:
|
||||
// - axes - the axes to update our map with
|
||||
void DxFontRenderData::_SetAxes(const std::unordered_map<std::wstring_view, float>& axes)
|
||||
{
|
||||
// Clear out the old vector and booleans in case this is a hot reload
|
||||
_axesVector = std::vector<DWRITE_FONT_AXIS_VALUE>{};
|
||||
_didUserSetAxes = false;
|
||||
_didUserSetItalic = false;
|
||||
|
||||
// Update our axis map with the provided axes
|
||||
if (!axes.empty())
|
||||
{
|
||||
// Store the weight aside: we will be creating a span of all the axes in the vector except the weight,
|
||||
// and then we will add the weight to the vector
|
||||
// We are doing this so that when the text attribute is bold, we can apply all the axes except the weight
|
||||
std::optional<DWRITE_FONT_AXIS_VALUE> weightAxis;
|
||||
|
||||
// Since we are calling an 'emplace_back' after creating the span,
|
||||
// there is a chance a reallocation happens (if the vector needs to grow), which would make the span point to
|
||||
// deallocated memory. To avoid this, make sure to reserve enough memory in the vector.
|
||||
_axesVector.reserve(axes.size());
|
||||
|
||||
#pragma warning(suppress : 26445) // the analyzer doesn't like reference to string_view
|
||||
for (const auto& [axis, value] : axes)
|
||||
{
|
||||
if (axis.length() == TAG_LENGTH)
|
||||
{
|
||||
const auto dwriteFontAxis = DWRITE_FONT_AXIS_VALUE{ DWRITE_MAKE_FONT_AXIS_TAG(til::at(axis, 0), til::at(axis, 1), til::at(axis, 2), til::at(axis, 3)), value };
|
||||
if (dwriteFontAxis.axisTag != DWRITE_FONT_AXIS_TAG_WEIGHT)
|
||||
{
|
||||
_axesVector.emplace_back(dwriteFontAxis);
|
||||
}
|
||||
else
|
||||
{
|
||||
weightAxis = dwriteFontAxis;
|
||||
}
|
||||
_didUserSetItalic |= dwriteFontAxis.axisTag == DWRITE_FONT_AXIS_TAG_ITALIC && value == 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the span, which has all the axes except the weight
|
||||
_axesVectorWithoutWeight = gsl::make_span(_axesVector);
|
||||
|
||||
// Add the weight axis to the vector if needed
|
||||
if (weightAxis)
|
||||
{
|
||||
_axesVector.emplace_back(weightAxis.value());
|
||||
}
|
||||
_didUserSetAxes = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Converts a DWRITE_FONT_STRETCH enum into the corresponding float value to
|
||||
// create a DWRITE_FONT_AXIS_VALUE with
|
||||
// Arguments:
|
||||
// - fontStretch: the old DWRITE_FONT_STRETCH enum to be converted into an axis value
|
||||
// Return value:
|
||||
// - The float value corresponding to the passed in fontStretch
|
||||
float DxFontRenderData::_FontStretchToWidthAxisValue(DWRITE_FONT_STRETCH fontStretch) noexcept
|
||||
{
|
||||
// 10 elements from DWRITE_FONT_STRETCH_UNDEFINED (0) to DWRITE_FONT_STRETCH_ULTRA_EXPANDED (9)
|
||||
static constexpr auto fontStretchEnumToVal = std::array{ 100.0f, 50.0f, 62.5f, 75.0f, 87.5f, 100.0f, 112.5f, 125.0f, 150.0f, 200.0f };
|
||||
|
||||
if (gsl::narrow_cast<size_t>(fontStretch) > fontStretchEnumToVal.size())
|
||||
{
|
||||
fontStretch = DWRITE_FONT_STRETCH_NORMAL;
|
||||
}
|
||||
|
||||
return til::at(fontStretchEnumToVal, fontStretch);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Converts a DWRITE_FONT_STYLE enum into the corresponding float value to
|
||||
// create a DWRITE_FONT_AXIS_VALUE with
|
||||
// Arguments:
|
||||
// - fontStyle: the old DWRITE_FONT_STYLE enum to be converted into an axis value
|
||||
// Return value:
|
||||
// - The float value corresponding to the passed in fontStyle
|
||||
float DxFontRenderData::_FontStyleToSlantFixedAxisValue(DWRITE_FONT_STYLE fontStyle) noexcept
|
||||
{
|
||||
// DWRITE_FONT_STYLE_NORMAL (0), DWRITE_FONT_STYLE_OBLIQUE (1), DWRITE_FONT_STYLE_ITALIC (2)
|
||||
static constexpr auto fontStyleEnumToVal = std::array{ 0.0f, -20.0f, -12.0f };
|
||||
|
||||
// Both DWRITE_FONT_STYLE_OBLIQUE and DWRITE_FONT_STYLE_ITALIC default to having slant.
|
||||
// Though an italic font technically need not have slant (there exist upright ones), the
|
||||
// vast majority of italic fonts are also slanted. Ideally the slant comes from the
|
||||
// 'slnt' value in the STAT or fvar table, or the post table italic angle.
|
||||
|
||||
if (gsl::narrow_cast<size_t>(fontStyle) > fontStyleEnumToVal.size())
|
||||
{
|
||||
fontStyle = DWRITE_FONT_STYLE_NORMAL;
|
||||
}
|
||||
|
||||
return til::at(fontStyleEnumToVal, fontStyle);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Fill any missing axis values that might be known but were unspecified, such as omitting
|
||||
// the 'wght' axis tag but specifying the old DWRITE_FONT_WEIGHT enum
|
||||
// - This function will only be called with a valid IDWriteTextFormat3
|
||||
// (on platforms where IDWriteTextFormat3 is supported)
|
||||
// Arguments:
|
||||
// - fontWeight: the old DWRITE_FONT_WEIGHT enum to be converted into an axis value
|
||||
// - fontStretch: the old DWRITE_FONT_STRETCH enum to be converted into an axis value
|
||||
// - fontStyle: the old DWRITE_FONT_STYLE enum to be converted into an axis value
|
||||
// - fontSize: the number to convert into an axis value
|
||||
// - format: the IDWriteTextFormat3 to get the defined axes from
|
||||
// Return value:
|
||||
// - The fully formed axes vector
|
||||
#pragma warning(suppress : 26429) // the analyzer doesn't detect that our FAIL_FAST_IF_NULL macro \
|
||||
// checks format for nullness
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> DxFontRenderData::GetAxisVector(const DWRITE_FONT_WEIGHT fontWeight,
|
||||
const DWRITE_FONT_STRETCH fontStretch,
|
||||
const DWRITE_FONT_STYLE fontStyle,
|
||||
IDWriteTextFormat3* format)
|
||||
{
|
||||
FAIL_FAST_IF_NULL(format);
|
||||
|
||||
const auto axesCount = format->GetFontAxisValueCount();
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> axesVector;
|
||||
axesVector.resize(axesCount);
|
||||
format->GetFontAxisValues(axesVector.data(), axesCount);
|
||||
|
||||
auto axisTagPresence = AxisTagPresence::None;
|
||||
for (const auto& fontAxisValue : axesVector)
|
||||
{
|
||||
switch (fontAxisValue.axisTag)
|
||||
{
|
||||
case DWRITE_FONT_AXIS_TAG_WEIGHT:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Weight);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_WIDTH:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Width);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_ITALIC:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Italic);
|
||||
break;
|
||||
case DWRITE_FONT_AXIS_TAG_SLANT:
|
||||
WI_SetFlag(axisTagPresence, AxisTagPresence::Slant);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Weight))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_WEIGHT, gsl::narrow<float>(fontWeight) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Width))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_WIDTH, _FontStretchToWidthAxisValue(fontStretch) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Italic))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_ITALIC, (fontStyle == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f) });
|
||||
}
|
||||
if (WI_IsFlagClear(axisTagPresence, AxisTagPresence::Slant))
|
||||
{
|
||||
axesVector.emplace_back(DWRITE_FONT_AXIS_VALUE{ DWRITE_FONT_AXIS_TAG_SLANT, _FontStyleToSlantFixedAxisValue(fontStyle) });
|
||||
}
|
||||
|
||||
return axesVector;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -546,13 +707,11 @@ bool DxFontRenderData::DidUserSetAxes() const noexcept
|
|||
// - None
|
||||
void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, FontInfo& actual, const int dpi)
|
||||
{
|
||||
std::wstring fontLocaleName = UserLocaleName();
|
||||
// This is the first attempt to resolve font face after `UpdateFont`.
|
||||
// Note that the following line may cause property changes _inside_ `_defaultFontInfo` because the desired font may not exist.
|
||||
// See the implementation of `ResolveFontFaceWithFallback` for details.
|
||||
const auto font = _ResolveFontWithFallback(desired.GetFaceName(), static_cast<DWRITE_FONT_WEIGHT>(desired.GetWeight()), DWRITE_FONT_STYLE_NORMAL);
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFace> face;
|
||||
THROW_IF_FAILED(font->CreateFontFace(&face));
|
||||
const Microsoft::WRL::ComPtr<IDWriteFontFace1> face = _defaultFontInfo.ResolveFontFaceWithFallback(_dwriteFactory.Get(), fontLocaleName);
|
||||
|
||||
DWRITE_FONT_METRICS1 fontMetrics;
|
||||
face->GetMetrics(&fontMetrics);
|
||||
|
@ -561,6 +720,9 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
|||
UINT16 spaceGlyphIndex;
|
||||
THROW_IF_FAILED(face->GetGlyphIndicesW(&spaceCodePoint, 1, &spaceGlyphIndex));
|
||||
|
||||
INT32 advanceInDesignUnits;
|
||||
THROW_IF_FAILED(face->GetDesignGlyphAdvances(1, &spaceGlyphIndex, &advanceInDesignUnits));
|
||||
|
||||
DWRITE_GLYPH_METRICS spaceMetrics = { 0 };
|
||||
THROW_IF_FAILED(face->GetDesignGlyphMetrics(&spaceGlyphIndex, 1, &spaceMetrics));
|
||||
|
||||
|
@ -584,7 +746,7 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
|||
// Now we play trickery with the font size. Scale by the DPI to get the height we expect.
|
||||
heightDesired *= (static_cast<float>(dpi) / static_cast<float>(USER_DEFAULT_SCREEN_DPI));
|
||||
|
||||
const float widthAdvance = static_cast<float>(spaceMetrics.advanceWidth) / fontMetrics.designUnitsPerEm;
|
||||
const float widthAdvance = static_cast<float>(advanceInDesignUnits) / fontMetrics.designUnitsPerEm;
|
||||
|
||||
// Use the real pixel height desired by the "em" factor for the width to get the number of pixels
|
||||
// we will need per character in width. This will almost certainly result in fractional X-dimension pixels.
|
||||
|
@ -670,13 +832,15 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
|||
|
||||
const COORD scaled = coordSize;
|
||||
|
||||
actual.SetFromEngine(desired.GetFaceName().c_str(),
|
||||
actual.SetFromEngine(_defaultFontInfo.GetFamilyName(),
|
||||
desired.GetFamily(),
|
||||
desired.GetWeight(),
|
||||
DefaultTextFormat()->GetFontWeight(),
|
||||
false,
|
||||
scaled,
|
||||
unscaled);
|
||||
|
||||
actual.SetFallback(_defaultFontInfo.GetFallback());
|
||||
|
||||
LineMetrics lineMetrics;
|
||||
// There is no font metric for the grid line width, so we use a small
|
||||
// multiple of the font size, which typically rounds to a pixel.
|
||||
|
@ -730,215 +894,31 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
|||
_glyphCell = actual.GetSize();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Attempts to locate the font given, but then begins falling back if we cannot find it.
|
||||
// - We'll try to fall back to Consolas with the given weight/stretch/style first,
|
||||
// then try Consolas again with normal weight/stretch/style,
|
||||
// and if nothing works, then we'll throw an error.
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// - localeName - Locale to search for appropriate fonts
|
||||
// Return Value:
|
||||
// - Smart pointer holding interface reference for queryable font data.
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFont> DxFontRenderData::_ResolveFontWithFallback(std::wstring familyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style)
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName)
|
||||
{
|
||||
if (familyName.empty())
|
||||
{
|
||||
familyName = L"Consolas";
|
||||
}
|
||||
if (!weight)
|
||||
{
|
||||
weight = DWRITE_FONT_WEIGHT_NORMAL;
|
||||
}
|
||||
if (!style)
|
||||
{
|
||||
style = DWRITE_FONT_STYLE_NORMAL;
|
||||
}
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> format;
|
||||
THROW_IF_FAILED(_dwriteFactory->CreateTextFormat(fontInfo.GetFamilyName().data(),
|
||||
fontInfo.GetNearbyCollection(),
|
||||
fontInfo.GetWeight(),
|
||||
fontInfo.GetStyle(),
|
||||
fontInfo.GetStretch(),
|
||||
_fontSize,
|
||||
localeName.data(),
|
||||
&format));
|
||||
|
||||
// First attempt to find exactly what the user asked for.
|
||||
Microsoft::WRL::ComPtr<IDWriteFont> font;
|
||||
|
||||
// GH#10211 - wrap this all up in a try/catch. If the nearby fonts are
|
||||
// corrupted, then we don't want to throw out of this top half of this
|
||||
// method. We still want to fall back to a font that's reasonable, below.
|
||||
try
|
||||
// If the OS supports IDWriteTextFormat3, set the font axes
|
||||
::Microsoft::WRL::ComPtr<IDWriteTextFormat3> format3;
|
||||
if (!FAILED(format->QueryInterface(IID_PPV_ARGS(&format3))))
|
||||
{
|
||||
font = _FindFont(familyName.c_str(), weight, style);
|
||||
|
||||
if (!font)
|
||||
if (_inhibitUserWeight && !_axesVectorWithoutWeight.empty())
|
||||
{
|
||||
// If we missed, try looking a little more by trimming the last word off the requested family name a few times.
|
||||
// Quite often, folks are specifying weights or something in the familyName and it causes failed resolution and
|
||||
// an unexpected error dialog. We theoretically could detect the weight words and convert them, but this
|
||||
// is the quick fix for the majority scenario.
|
||||
// The long/full fix is backlogged to GH#9744
|
||||
// Also this doesn't count as a fallback because we don't want to annoy folks with the warning dialog over
|
||||
// this resolution.
|
||||
while (!font && !familyName.empty())
|
||||
{
|
||||
const auto lastSpace = familyName.find_last_of(UNICODE_SPACE);
|
||||
|
||||
// value is unsigned and npos will be greater than size.
|
||||
// if we didn't find anything to trim, leave.
|
||||
if (lastSpace >= familyName.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// trim string down to just before the found space
|
||||
// (space found at 6... trim from 0 for 6 length will give us 0-5 as the new string)
|
||||
familyName = familyName.substr(0, lastSpace);
|
||||
|
||||
// Try to find it with the shortened family name
|
||||
font = _FindFont(familyName.c_str(), weight, style);
|
||||
}
|
||||
format3->SetFontAxisValues(_axesVectorWithoutWeight.data(), gsl::narrow<uint32_t>(_axesVectorWithoutWeight.size()));
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// Alright, if our quick shot at trimming didn't work either...
|
||||
// move onto looking up a font from our hardcoded list of fonts
|
||||
// that should really always be available.
|
||||
if (!font)
|
||||
{
|
||||
for (const auto fallbackFont : FALLBACK_FONT_FACES)
|
||||
else if (!_inhibitUserWeight && !_axesVector.empty())
|
||||
{
|
||||
// With these fonts, don't attempt the nearby lookup. We're looking
|
||||
// for system fonts only. If one of the nearby fonts is causing us
|
||||
// problems (like in GH#10211), then we don't want to go anywhere
|
||||
|
||||
// near it in this part.
|
||||
font = _FindFont(fallbackFont, weight, style);
|
||||
if (font)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
font = _FindFont(fallbackFont, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL);
|
||||
if (font)
|
||||
{
|
||||
break;
|
||||
}
|
||||
format3->SetFontAxisValues(_axesVector.data(), gsl::narrow<uint32_t>(_axesVector.size()));
|
||||
}
|
||||
}
|
||||
|
||||
THROW_HR_IF_NULL(E_FAIL, font);
|
||||
return font;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Locates a suitable font face from the given information
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// - localeName - Locale to search for appropriate fonts
|
||||
// Return Value:
|
||||
// - Smart pointer holding interface reference for queryable font data.
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFont> DxFontRenderData::_FindFont(const wchar_t* familyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteFont> font;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteFontCollection> fontCollection;
|
||||
THROW_IF_FAILED(_dwriteFactory->GetSystemFontCollection(&fontCollection, false));
|
||||
|
||||
UINT32 familyIndex;
|
||||
BOOL familyExists;
|
||||
THROW_IF_FAILED(fontCollection->FindFamilyName(familyName, &familyIndex, &familyExists));
|
||||
|
||||
// If the system collection missed, try the files sitting next to our binary.
|
||||
if (!familyExists)
|
||||
{
|
||||
// May be null on OS below Windows 10. If null, just skip the attempt.
|
||||
if (const auto nearbyCollection = _NearbyCollection())
|
||||
{
|
||||
THROW_IF_FAILED(nearbyCollection->FindFamilyName(familyName, &familyIndex, &familyExists));
|
||||
fontCollection = nearbyCollection;
|
||||
}
|
||||
}
|
||||
|
||||
if (familyExists)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IDWriteFontFamily> fontFamily;
|
||||
THROW_IF_FAILED(fontCollection->GetFontFamily(familyIndex, &fontFamily));
|
||||
THROW_IF_FAILED(fontFamily->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &font));
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Creates a DirectWrite font collection of font files that are sitting next to the running
|
||||
// binary (in the same directory as the EXE).
|
||||
// Arguments:
|
||||
// - dwriteFactory - The DWrite factory to use
|
||||
// Return Value:
|
||||
// - DirectWrite font collection. May be null if one cannot be created.
|
||||
[[nodiscard]] IDWriteFontCollection* DxFontRenderData::_NearbyCollection()
|
||||
{
|
||||
if (_nearbyFontCollection)
|
||||
{
|
||||
return _nearbyFontCollection.Get();
|
||||
}
|
||||
|
||||
// The convenience interfaces for loading fonts from files
|
||||
// are only available on Windows 10+.
|
||||
::Microsoft::WRL::ComPtr<IDWriteFactory6> factory6;
|
||||
if (FAILED(_dwriteFactory->QueryInterface<IDWriteFactory6>(&factory6)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> systemFontCollection;
|
||||
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, &systemFontCollection, 0));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> systemFontSet;
|
||||
THROW_IF_FAILED(systemFontCollection->GetFontSet(&systemFontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSetBuilder2> fontSetBuilder2;
|
||||
THROW_IF_FAILED(factory6->CreateFontSetBuilder(&fontSetBuilder2));
|
||||
|
||||
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.Get()));
|
||||
|
||||
// Magic static so we only attempt to grovel the hard disk once no matter how many instances
|
||||
// of the font collection itself we require.
|
||||
static const auto knownPaths = s_GetNearbyFonts();
|
||||
for (auto& p : knownPaths)
|
||||
{
|
||||
fontSetBuilder2->AddFontFile(p.c_str());
|
||||
}
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontSet> fontSet;
|
||||
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(&fontSet));
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection1> fontCollection;
|
||||
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.Get(), &fontCollection));
|
||||
|
||||
_nearbyFontCollection = fontCollection;
|
||||
return _nearbyFontCollection.Get();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Digs through the directory that the current executable is running within to find
|
||||
// any TTF files sitting next to it.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - Iterable collection of filesystem paths, one per font file that was found
|
||||
[[nodiscard]] std::vector<std::filesystem::path> DxFontRenderData::s_GetNearbyFonts()
|
||||
{
|
||||
std::vector<std::filesystem::path> paths;
|
||||
|
||||
// Find the directory we're running from then enumerate all the TTF files
|
||||
// sitting next to us.
|
||||
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
|
||||
const auto folder{ module.parent_path() };
|
||||
|
||||
for (const auto& p : std::filesystem::directory_iterator(folder))
|
||||
{
|
||||
if (til::ends_with_insensitive_ascii(p.path().native(), L".ttf"))
|
||||
{
|
||||
paths.push_back(p.path());
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
return format;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../renderer/inc/FontInfoDesired.hpp"
|
||||
#include "DxFontInfo.h"
|
||||
#include "BoxDrawingEffect.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
|
@ -45,69 +46,97 @@ namespace Microsoft::Console::Render
|
|||
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFallback> SystemFontFallback();
|
||||
|
||||
[[nodiscard]] til::size GlyphCell() const noexcept;
|
||||
[[nodiscard]] LineMetrics GetLineMetrics() const noexcept;
|
||||
// A locale that can be used on construction of assorted DX objects that want to know one.
|
||||
[[nodiscard]] std::wstring UserLocaleName();
|
||||
|
||||
[[nodiscard]] til::size GlyphCell() noexcept;
|
||||
[[nodiscard]] LineMetrics GetLineMetrics() noexcept;
|
||||
|
||||
// The weight of default font
|
||||
[[nodiscard]] DWRITE_FONT_WEIGHT DefaultFontWeight() const noexcept;
|
||||
[[nodiscard]] DWRITE_FONT_WEIGHT DefaultFontWeight() noexcept;
|
||||
|
||||
// The style of default font
|
||||
[[nodiscard]] static DWRITE_FONT_STYLE DefaultFontStyle() noexcept;
|
||||
[[nodiscard]] DWRITE_FONT_STYLE DefaultFontStyle() noexcept;
|
||||
|
||||
// The stretch of default font
|
||||
[[nodiscard]] static DWRITE_FONT_STRETCH DefaultFontStretch() noexcept;
|
||||
[[nodiscard]] DWRITE_FONT_STRETCH DefaultFontStretch() noexcept;
|
||||
|
||||
// The font features of the default font
|
||||
[[nodiscard]] const std::vector<DWRITE_FONT_FEATURE>& DefaultFontFeatures() const noexcept;
|
||||
|
||||
// The DirectWrite format object representing the size and other text properties to be applied (by default)
|
||||
[[nodiscard]] IDWriteTextFormat* DefaultTextFormat() const noexcept;
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> DefaultTextFormat();
|
||||
|
||||
// The DirectWrite font face to use while calculating layout (by default)
|
||||
[[nodiscard]] IDWriteFontFace1* DefaultFontFace() const noexcept;
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> DefaultFontFace();
|
||||
|
||||
// Box drawing scaling effects that are cached for the base font across layouts
|
||||
[[nodiscard]] IBoxDrawingEffect* DefaultBoxDrawingEffect();
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IBoxDrawingEffect> DefaultBoxDrawingEffect();
|
||||
|
||||
// The attributed variants of the format object representing the size and other text properties
|
||||
[[nodiscard]] IDWriteTextFormat* TextFormatWithAttribute(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept;
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteTextFormat> TextFormatWithAttribute(DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
// The attributed variants of the font face to use while calculating layout
|
||||
[[nodiscard]] IDWriteFontFace1* FontFaceWithAttribute(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept;
|
||||
|
||||
[[nodiscard]] const std::vector<DWRITE_FONT_AXIS_VALUE>& GetAxisVector(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style) const noexcept;
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFontFace1> FontFaceWithAttribute(DWRITE_FONT_WEIGHT weight,
|
||||
DWRITE_FONT_STYLE style,
|
||||
DWRITE_FONT_STRETCH stretch);
|
||||
|
||||
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& desired, FontInfo& fiFontInfo, const int dpi, const std::unordered_map<std::wstring_view, uint32_t>& features = {}, const std::unordered_map<std::wstring_view, float>& axes = {}) noexcept;
|
||||
|
||||
[[nodiscard]] static HRESULT s_CalculateBoxEffect(IDWriteTextFormat* format, size_t widthPixels, IDWriteFontFace1* face, float fontScale, IBoxDrawingEffect** effect) noexcept;
|
||||
[[nodiscard]] static HRESULT STDMETHODCALLTYPE s_CalculateBoxEffect(IDWriteTextFormat* format, size_t widthPixels, IDWriteFontFace1* face, float fontScale, IBoxDrawingEffect** effect) noexcept;
|
||||
|
||||
bool DidUserSetFeatures() const noexcept;
|
||||
bool DidUserSetAxes() const noexcept;
|
||||
void InhibitUserWeight(bool inhibitUserWeight) noexcept;
|
||||
bool DidUserSetItalic() const noexcept;
|
||||
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> GetAxisVector(const DWRITE_FONT_WEIGHT fontWeight,
|
||||
const DWRITE_FONT_STRETCH fontStretch,
|
||||
const DWRITE_FONT_STYLE fontStyle,
|
||||
IDWriteTextFormat3* format);
|
||||
|
||||
private:
|
||||
void _RefreshUserLocaleName();
|
||||
void _BuildFontRenderData(const FontInfoDesired& desired, FontInfo& actual, const int dpi);
|
||||
::Microsoft::WRL::ComPtr<IDWriteFont> _ResolveFontWithFallback(std::wstring familyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style);
|
||||
[[nodiscard]] Microsoft::WRL::ComPtr<IDWriteFont> _FindFont(const wchar_t* familyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style);
|
||||
[[nodiscard]] IDWriteFontCollection* _NearbyCollection();
|
||||
[[nodiscard]] static std::vector<std::filesystem::path> s_GetNearbyFonts();
|
||||
using FontAttributeMapKey = uint32_t;
|
||||
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFace1> _fontFaces[2][2];
|
||||
::Microsoft::WRL::ComPtr<IDWriteTextFormat> _textFormats[2][2];
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> _textFormatAxes[2][2];
|
||||
bool _inhibitUserWeight{ false };
|
||||
bool _didUserSetItalic{ false };
|
||||
bool _didUserSetFeatures{ false };
|
||||
bool _didUserSetAxes{ false };
|
||||
// The font features to apply to the text
|
||||
std::vector<DWRITE_FONT_FEATURE> _featureVector;
|
||||
|
||||
// The font axes to apply to the text
|
||||
std::vector<DWRITE_FONT_AXIS_VALUE> _axesVector;
|
||||
gsl::span<DWRITE_FONT_AXIS_VALUE> _axesVectorWithoutWeight;
|
||||
|
||||
// We use this to identify font variants with different attributes.
|
||||
static FontAttributeMapKey _ToMapKey(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch) noexcept
|
||||
{
|
||||
return (weight << 16) | (style << 8) | stretch;
|
||||
};
|
||||
|
||||
void _SetFeatures(const std::unordered_map<std::wstring_view, uint32_t>& features);
|
||||
void _SetAxes(const std::unordered_map<std::wstring_view, float>& axes);
|
||||
float _FontStretchToWidthAxisValue(DWRITE_FONT_STRETCH fontStretch) noexcept;
|
||||
float _FontStyleToSlantFixedAxisValue(DWRITE_FONT_STYLE fontStyle) noexcept;
|
||||
void _BuildFontRenderData(const FontInfoDesired& desired, FontInfo& actual, const int dpi);
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> _BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName);
|
||||
|
||||
std::unordered_map<FontAttributeMapKey, ::Microsoft::WRL::ComPtr<IDWriteTextFormat>> _textFormatMap;
|
||||
std::unordered_map<FontAttributeMapKey, ::Microsoft::WRL::ComPtr<IDWriteFontFace1>> _fontFaceMap;
|
||||
|
||||
::Microsoft::WRL::ComPtr<IBoxDrawingEffect> _boxDrawingEffect;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontFallback> _systemFontFallback;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFontCollection> _nearbyFontCollection;
|
||||
::Microsoft::WRL::ComPtr<IDWriteFactory1> _dwriteFactory;
|
||||
::Microsoft::WRL::ComPtr<IDWriteTextAnalyzer1> _dwriteTextAnalyzer;
|
||||
|
||||
wil::unique_process_heap_string _userLocaleName;
|
||||
std::wstring _userLocaleName;
|
||||
DxFontInfo _defaultFontInfo;
|
||||
til::size _glyphCell;
|
||||
DWRITE_LINE_SPACING _lineSpacing;
|
||||
LineMetrics _lineMetrics;
|
||||
DWRITE_FONT_WEIGHT _userFontWeight;
|
||||
float _fontSize;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -941,7 +941,7 @@ try
|
|||
{
|
||||
return _dwriteFactory->CreateTextLayout(string,
|
||||
gsl::narrow<UINT32>(stringLength),
|
||||
_fontRenderData->DefaultTextFormat(),
|
||||
_fontRenderData->DefaultTextFormat().Get(),
|
||||
_displaySizePixels.width<float>(),
|
||||
_fontRenderData->GlyphCell().height() != 0 ? _fontRenderData->GlyphCell().height<float>() : _displaySizePixels.height<float>(),
|
||||
ppTextLayout);
|
||||
|
@ -1502,7 +1502,7 @@ void DxEngine::WaitUntilCanRender() noexcept
|
|||
{
|
||||
// Throttle the DxEngine a bit down to ~60 FPS.
|
||||
// This improves throughput for rendering complex or colored text.
|
||||
//Sleep(8);
|
||||
Sleep(8);
|
||||
|
||||
if (_swapChainFrameLatencyWaitableObject)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<ClCompile Include="..\BoxDrawingEffect.cpp" />
|
||||
<ClCompile Include="..\CustomTextLayout.cpp" />
|
||||
<ClCompile Include="..\CustomTextRenderer.cpp" />
|
||||
<ClCompile Include="..\DxFontInfo.cpp" />
|
||||
<ClCompile Include="..\DxFontRenderData.cpp" />
|
||||
<ClCompile Include="..\DxRenderer.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
|
@ -28,6 +29,7 @@
|
|||
<ClInclude Include="..\BoxDrawingEffect.h" />
|
||||
<ClInclude Include="..\CustomTextLayout.h" />
|
||||
<ClInclude Include="..\CustomTextRenderer.h" />
|
||||
<ClInclude Include="..\DxFontInfo.h" />
|
||||
<ClInclude Include="..\DxFontRenderData.h" />
|
||||
<ClInclude Include="..\DxRenderer.hpp" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
|
|
|
@ -33,6 +33,7 @@ INCLUDES = \
|
|||
SOURCES = \
|
||||
$(SOURCES) \
|
||||
..\DxRenderer.cpp \
|
||||
..\DxFontInfo.cpp \
|
||||
..\DxFontRenderData.cpp \
|
||||
..\CustomTextRenderer.cpp \
|
||||
..\CustomTextLayout.cpp \
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
const bool fSetDefaultRasterFont,
|
||||
const COORD coordSize,
|
||||
const COORD coordSizeUnscaled) noexcept;
|
||||
bool GetFallback() const noexcept;
|
||||
void SetFallback(const bool didFallback) noexcept;
|
||||
void ValidateFont() noexcept;
|
||||
|
||||
|
|
|
@ -2250,7 +2250,7 @@ bool AdaptDispatch::SetCursorColor(const COLORREF cursorColor)
|
|||
return false;
|
||||
}
|
||||
|
||||
return _pConApi->SetCursorColor(cursorColor);
|
||||
return _pConApi->SetColorTableEntry(TextColor::CURSOR_COLOR, cursorColor);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -2273,7 +2273,7 @@ bool AdaptDispatch::SetClipboard(const std::wstring_view /*content*/) noexcept
|
|||
// True if handled successfully. False otherwise.
|
||||
bool AdaptDispatch::SetColorTableEntry(const size_t tableIndex, const DWORD dwColor)
|
||||
{
|
||||
const bool success = _pConApi->PrivateSetColorTableEntry(tableIndex, dwColor);
|
||||
const bool success = _pConApi->SetColorTableEntry(tableIndex, dwColor);
|
||||
|
||||
// If we're a conpty, always return false, so that we send the updated color
|
||||
// value to the terminal. Still handle the sequence so apps that use
|
||||
|
@ -2293,10 +2293,10 @@ bool AdaptDispatch::SetColorTableEntry(const size_t tableIndex, const DWORD dwCo
|
|||
// - dwColor: The new RGB color value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// True if handled successfully. False otherwise.
|
||||
bool Microsoft::Console::VirtualTerminal::AdaptDispatch::SetDefaultForeground(const DWORD dwColor)
|
||||
bool AdaptDispatch::SetDefaultForeground(const DWORD dwColor)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateSetDefaultForeground(dwColor);
|
||||
success = _pConApi->SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, dwColor);
|
||||
|
||||
// If we're a conpty, always return false, so that we send the updated color
|
||||
// value to the terminal. Still handle the sequence so apps that use
|
||||
|
@ -2316,10 +2316,10 @@ bool Microsoft::Console::VirtualTerminal::AdaptDispatch::SetDefaultForeground(co
|
|||
// - dwColor: The new RGB color value to use, as a COLORREF, format 0x00BBGGRR.
|
||||
// Return Value:
|
||||
// True if handled successfully. False otherwise.
|
||||
bool Microsoft::Console::VirtualTerminal::AdaptDispatch::SetDefaultBackground(const DWORD dwColor)
|
||||
bool AdaptDispatch::SetDefaultBackground(const DWORD dwColor)
|
||||
{
|
||||
bool success = true;
|
||||
success = _pConApi->PrivateSetDefaultBackground(dwColor);
|
||||
success = _pConApi->SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, dwColor);
|
||||
|
||||
// If we're a conpty, always return false, so that we send the updated color
|
||||
// value to the terminal. Still handle the sequence so apps that use
|
||||
|
|
|
@ -72,7 +72,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
virtual bool PrivateClearBuffer() = 0;
|
||||
virtual bool GetUserDefaultCursorStyle(CursorType& style) = 0;
|
||||
virtual bool SetCursorStyle(const CursorType style) = 0;
|
||||
virtual bool SetCursorColor(const COLORREF color) = 0;
|
||||
virtual bool PrivateWriteConsoleControlInput(const KeyEvent key) = 0;
|
||||
virtual bool PrivateRefreshWindow() = 0;
|
||||
|
||||
|
@ -87,10 +86,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
|
||||
virtual bool MoveToBottom() const = 0;
|
||||
|
||||
virtual bool PrivateGetColorTableEntry(const size_t index, COLORREF& value) const = 0;
|
||||
virtual bool PrivateSetColorTableEntry(const size_t index, const COLORREF value) const = 0;
|
||||
virtual bool PrivateSetDefaultForeground(const COLORREF value) const = 0;
|
||||
virtual bool PrivateSetDefaultBackground(const COLORREF value) const = 0;
|
||||
virtual COLORREF GetColorTableEntry(const size_t tableIndex) const = 0;
|
||||
virtual bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) = 0;
|
||||
|
||||
virtual bool PrivateFillRegion(const COORD startPosition,
|
||||
const size_t fillLength,
|
||||
|
|
|
@ -370,16 +370,6 @@ public:
|
|||
return _setCursorStyleResult;
|
||||
}
|
||||
|
||||
bool SetCursorColor(const COLORREF cursorColor) override
|
||||
{
|
||||
Log::Comment(L"SetCursorColor MOCK called...");
|
||||
if (_setCursorColorResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedCursorColor, cursorColor);
|
||||
}
|
||||
return _setCursorColorResult;
|
||||
}
|
||||
|
||||
bool PrivateRefreshWindow() override
|
||||
{
|
||||
Log::Comment(L"PrivateRefreshWindow MOCK called...");
|
||||
|
@ -438,53 +428,31 @@ public:
|
|||
return _moveToBottomResult;
|
||||
}
|
||||
|
||||
bool PrivateGetColorTableEntry(const size_t index, COLORREF& value) const noexcept override
|
||||
COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept override
|
||||
{
|
||||
Log::Comment(L"PrivateGetColorTableEntry MOCK called...");
|
||||
Log::Comment(L"GetColorTableEntry MOCK called...");
|
||||
|
||||
if (_privateGetColorTableEntryResult)
|
||||
if (_getColorTableEntryResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedColorTableIndex, index);
|
||||
VERIFY_ARE_EQUAL(_expectedColorTableIndex, tableIndex);
|
||||
// Simply returning the index as the color value makes it easy for
|
||||
// tests to confirm that they've received the color they expected.
|
||||
value = gsl::narrow_cast<COLORREF>(index);
|
||||
return gsl::narrow_cast<COLORREF>(tableIndex);
|
||||
}
|
||||
|
||||
return _privateGetColorTableEntryResult;
|
||||
return INVALID_COLOR;
|
||||
}
|
||||
|
||||
bool PrivateSetColorTableEntry(const size_t index, const COLORREF value) const noexcept override
|
||||
bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept override
|
||||
{
|
||||
Log::Comment(L"PrivateSetColorTableEntry MOCK called...");
|
||||
if (_privateSetColorTableEntryResult)
|
||||
Log::Comment(L"SetColorTableEntry MOCK called...");
|
||||
if (_setColorTableEntryResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedColorTableIndex, index);
|
||||
VERIFY_ARE_EQUAL(_expectedColorValue, value);
|
||||
VERIFY_ARE_EQUAL(_expectedColorTableIndex, tableIndex);
|
||||
VERIFY_ARE_EQUAL(_expectedColorValue, color);
|
||||
}
|
||||
|
||||
return _privateSetColorTableEntryResult;
|
||||
}
|
||||
|
||||
bool PrivateSetDefaultForeground(const COLORREF value) const noexcept override
|
||||
{
|
||||
Log::Comment(L"PrivateSetDefaultForeground MOCK called...");
|
||||
if (_privateSetDefaultForegroundResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedDefaultForegroundColorValue, value);
|
||||
}
|
||||
|
||||
return _privateSetDefaultForegroundResult;
|
||||
}
|
||||
|
||||
bool PrivateSetDefaultBackground(const COLORREF value) const noexcept override
|
||||
{
|
||||
Log::Comment(L"PrivateSetDefaultForeground MOCK called...");
|
||||
if (_privateSetDefaultBackgroundResult)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(_expectedDefaultBackgroundColorValue, value);
|
||||
}
|
||||
|
||||
return _privateSetDefaultBackgroundResult;
|
||||
return _setColorTableEntryResult;
|
||||
}
|
||||
|
||||
bool PrivateFillRegion(const COORD /*startPosition*/,
|
||||
|
@ -739,23 +707,15 @@ public:
|
|||
std::wstring_view _expectedWindowTitle{};
|
||||
bool _setCursorStyleResult = false;
|
||||
CursorType _expectedCursorStyle;
|
||||
bool _setCursorColorResult = false;
|
||||
COLORREF _expectedCursorColor = 0;
|
||||
bool _setConsoleOutputCPResult = false;
|
||||
bool _getConsoleOutputCPResult = false;
|
||||
bool _moveToBottomResult = false;
|
||||
|
||||
bool _privateGetColorTableEntryResult = false;
|
||||
bool _privateSetColorTableEntryResult = false;
|
||||
bool _getColorTableEntryResult = false;
|
||||
bool _setColorTableEntryResult = false;
|
||||
size_t _expectedColorTableIndex = SIZE_MAX;
|
||||
COLORREF _expectedColorValue = INVALID_COLOR;
|
||||
|
||||
bool _privateSetDefaultForegroundResult = false;
|
||||
COLORREF _expectedDefaultForegroundColorValue = INVALID_COLOR;
|
||||
|
||||
bool _privateSetDefaultBackgroundResult = false;
|
||||
COLORREF _expectedDefaultBackgroundColorValue = INVALID_COLOR;
|
||||
|
||||
SIZE _expectedCellSize = {};
|
||||
|
||||
private:
|
||||
|
@ -2306,7 +2266,7 @@ public:
|
|||
VTParameter rgOptions[16];
|
||||
size_t cOptions = 3;
|
||||
|
||||
_testGetSet->_privateGetColorTableEntryResult = true;
|
||||
_testGetSet->_getColorTableEntryResult = true;
|
||||
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
|
||||
|
||||
Log::Comment(L"Test 1: Change Foreground");
|
||||
|
@ -2356,7 +2316,7 @@ public:
|
|||
|
||||
VTParameter rgOptions[16];
|
||||
|
||||
_testGetSet->_privateGetColorTableEntryResult = true;
|
||||
_testGetSet->_getColorTableEntryResult = true;
|
||||
_testGetSet->_expectedAttribute = _testGetSet->_attribute;
|
||||
|
||||
Log::Comment(L"Test 1: Change Indexed Foreground with missing index parameter");
|
||||
|
@ -2399,7 +2359,7 @@ public:
|
|||
{
|
||||
_testGetSet->PrepData();
|
||||
|
||||
_testGetSet->_privateSetColorTableEntryResult = true;
|
||||
_testGetSet->_setColorTableEntryResult = true;
|
||||
const auto testColor = RGB(1, 2, 3);
|
||||
_testGetSet->_expectedColorValue = testColor;
|
||||
|
||||
|
@ -2409,7 +2369,7 @@ public:
|
|||
VERIFY_IS_TRUE(_pDispatch.get()->SetColorTableEntry(i, testColor));
|
||||
}
|
||||
|
||||
// Test in pty mode - we should fail, but PrivateSetColorTableEntry should still be called
|
||||
// Test in pty mode - we should fail, but SetColorTableEntry should still be called
|
||||
_testGetSet->_isPty = true;
|
||||
|
||||
_testGetSet->_expectedColorTableIndex = 15; // Windows BRIGHT_WHITE
|
||||
|
|
|
@ -542,7 +542,7 @@ 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
|
||||
bool TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept
|
||||
{
|
||||
return _mouseInputState.inAlternateBuffer &&
|
||||
_inputMode.test(Mode::AlternateScroll) &&
|
||||
|
@ -555,7 +555,7 @@ 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
|
||||
bool TerminalInput::_SendAlternateScroll(const short delta) const noexcept
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
|
|
|
@ -250,13 +250,13 @@ 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::SetInputMode(const Mode mode, const bool enabled)
|
||||
void TerminalInput::SetInputMode(const Mode mode, const bool enabled) noexcept
|
||||
{
|
||||
// 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);
|
||||
_inputMode.reset(Mode::DefaultMouseTracking, Mode::ButtonEventMouseTracking, Mode::AnyEventMouseTracking);
|
||||
_mouseInputState.lastPos = { -1, -1 };
|
||||
_mouseInputState.lastButton = 0;
|
||||
}
|
||||
|
@ -265,13 +265,13 @@ void TerminalInput::SetInputMode(const Mode mode, const bool enabled)
|
|||
// when enabling a new encoding - not when disabling.
|
||||
if ((mode == Mode::Utf8MouseEncoding || mode == Mode::SgrMouseEncoding) && enabled)
|
||||
{
|
||||
_inputMode.reset_all(Mode::Utf8MouseEncoding, Mode::SgrMouseEncoding);
|
||||
_inputMode.reset(Mode::Utf8MouseEncoding, Mode::SgrMouseEncoding);
|
||||
}
|
||||
|
||||
_inputMode.set(mode, enabled);
|
||||
}
|
||||
|
||||
bool TerminalInput::GetInputMode(const Mode mode) const
|
||||
bool TerminalInput::GetInputMode(const Mode mode) const noexcept
|
||||
{
|
||||
return _inputMode.test(mode);
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
AlternateScroll
|
||||
};
|
||||
|
||||
void SetInputMode(const Mode mode, const bool enabled);
|
||||
bool GetInputMode(const Mode mode) const;
|
||||
void SetInputMode(const Mode mode, const bool enabled) noexcept;
|
||||
bool GetInputMode(const Mode mode) const noexcept;
|
||||
void ForceDisableWin32InputMode(const bool win32InputMode) noexcept;
|
||||
|
||||
#pragma region MouseInput
|
||||
|
@ -127,8 +127,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
const short modifierKeyState,
|
||||
const short delta);
|
||||
|
||||
bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const;
|
||||
bool _SendAlternateScroll(const short delta) const;
|
||||
bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
|
||||
bool _SendAlternateScroll(const short delta) const noexcept;
|
||||
|
||||
static constexpr unsigned int s_GetPressedButton(const MouseButtonState state) noexcept;
|
||||
#pragma endregion
|
||||
|
|
|
@ -23,12 +23,12 @@ StateMachine::StateMachine(std::unique_ptr<IStateMachineEngine> engine) :
|
|||
_ActionClear();
|
||||
}
|
||||
|
||||
void StateMachine::SetParserMode(const Mode mode, const bool enabled)
|
||||
void StateMachine::SetParserMode(const Mode mode, const bool enabled) noexcept
|
||||
{
|
||||
_parserMode.set(mode, enabled);
|
||||
}
|
||||
|
||||
bool StateMachine::GetParserMode(const Mode mode) const
|
||||
bool StateMachine::GetParserMode(const Mode mode) const noexcept
|
||||
{
|
||||
return _parserMode.test(mode);
|
||||
}
|
||||
|
|
|
@ -48,8 +48,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||
Ansi,
|
||||
};
|
||||
|
||||
void SetParserMode(const Mode mode, const bool enabled);
|
||||
bool GetParserMode(const Mode mode) const;
|
||||
void SetParserMode(const Mode mode, const bool enabled) noexcept;
|
||||
bool GetParserMode(const Mode mode) const noexcept;
|
||||
|
||||
void ProcessCharacter(const wchar_t wch);
|
||||
void ProcessString(const std::wstring_view string);
|
||||
|
|
|
@ -24,19 +24,19 @@ class EnumSetTests
|
|||
{
|
||||
Log::Comment(L"Default constructor with no bits set");
|
||||
til::enumset<Flags> flags;
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.bits());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(L"Constructor with bit 3 set");
|
||||
til::enumset<Flags> flags{ Flags::Three };
|
||||
VERIFY_ARE_EQUAL(0b01000u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b01000u, flags.bits());
|
||||
}
|
||||
|
||||
{
|
||||
Log::Comment(L"Constructor with bits 0, 2, and 4 set");
|
||||
til::enumset<Flags> flags{ Flags::Zero, Flags::Two, Flags::Four };
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.bits());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,39 +53,39 @@ class EnumSetTests
|
|||
|
||||
Log::Comment(L"Start with no bits set");
|
||||
til::enumset<Flags> flags;
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.bits());
|
||||
|
||||
Log::Comment(L"Set bit 2 to true");
|
||||
flags.set(Flags::Two);
|
||||
VERIFY_ARE_EQUAL(0b00100u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b00100u, flags.bits());
|
||||
|
||||
Log::Comment(L"Flip bit 4 to true");
|
||||
flags.flip(Flags::Four);
|
||||
VERIFY_ARE_EQUAL(0b10100u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b10100u, flags.bits());
|
||||
|
||||
Log::Comment(L"Set bit 0 to true");
|
||||
flags.set(Flags::Zero);
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.to_ulong());
|
||||
flags.set(Flags::Zero, true);
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.bits());
|
||||
|
||||
Log::Comment(L"Reset bit 2 to false, leaving 0 and 4 true");
|
||||
flags.reset(Flags::Two);
|
||||
VERIFY_ARE_EQUAL(0b10001u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b10001u, flags.bits());
|
||||
|
||||
Log::Comment(L"Set bit 0 to false, leaving 4 true");
|
||||
flags.set(Flags::Zero, false);
|
||||
VERIFY_ARE_EQUAL(0b10000u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b10000u, flags.bits());
|
||||
|
||||
Log::Comment(L"Flip bit 4, leaving all bits false ");
|
||||
flags.flip(Flags::Four);
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.bits());
|
||||
|
||||
Log::Comment(L"Set bits 0, 3, and 2");
|
||||
flags.set_all(Flags::Zero, Flags::Three, Flags::Two);
|
||||
VERIFY_ARE_EQUAL(0b01101u, flags.to_ulong());
|
||||
flags.set(Flags::Zero, Flags::Three, Flags::Two);
|
||||
VERIFY_ARE_EQUAL(0b01101u, flags.bits());
|
||||
|
||||
Log::Comment(L"Reset bits 3, 4 (already reset), and 0, leaving 2 true");
|
||||
flags.reset_all(Flags::Three, Flags::Four, Flags::Zero);
|
||||
VERIFY_ARE_EQUAL(0b00100u, flags.to_ulong());
|
||||
flags.reset(Flags::Three, Flags::Four, Flags::Zero);
|
||||
VERIFY_ARE_EQUAL(0b00100u, flags.bits());
|
||||
}
|
||||
|
||||
TEST_METHOD(TestMethods)
|
||||
|
@ -101,15 +101,13 @@ class EnumSetTests
|
|||
|
||||
Log::Comment(L"Start with bits 0, 2, and 4 set");
|
||||
til::enumset<Flags> flags{ Flags::Zero, Flags::Two, Flags::Four };
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.to_ulong());
|
||||
VERIFY_ARE_EQUAL(0b10101u, flags.bits());
|
||||
|
||||
Log::Comment(L"Test bits 1 and 2 with the test method");
|
||||
Log::Comment(L"Test bits 1 through 4 with the test method");
|
||||
VERIFY_IS_FALSE(flags.test(Flags::One));
|
||||
VERIFY_IS_TRUE(flags.test(Flags::Two));
|
||||
|
||||
Log::Comment(L"Test bit 3 and 4 with the array operator");
|
||||
VERIFY_IS_FALSE(flags[Flags::Three]);
|
||||
VERIFY_IS_TRUE(flags[Flags::Four]);
|
||||
VERIFY_IS_FALSE(flags.test(Flags::Three));
|
||||
VERIFY_IS_TRUE(flags.test(Flags::Four));
|
||||
|
||||
Log::Comment(L"Test if any bits are set");
|
||||
VERIFY_IS_TRUE(flags.any());
|
||||
|
@ -125,45 +123,4 @@ class EnumSetTests
|
|||
Log::Comment(L"Test if both bits 0 and 3 are set");
|
||||
VERIFY_IS_FALSE(flags.all(Flags::Zero, Flags::Three));
|
||||
}
|
||||
|
||||
TEST_METHOD(ArrayReferenceOperator)
|
||||
{
|
||||
enum class Flags
|
||||
{
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four
|
||||
};
|
||||
|
||||
Log::Comment(L"Start with no bits set");
|
||||
til::enumset<Flags> flags;
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
|
||||
Log::Comment(L"Test bit 3 reference is false");
|
||||
auto reference = flags[Flags::Three];
|
||||
VERIFY_IS_FALSE(reference);
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
|
||||
Log::Comment(L"Set bit 3 reference to true");
|
||||
flags.set(Flags::Three);
|
||||
VERIFY_IS_TRUE(reference);
|
||||
VERIFY_ARE_EQUAL(0b01000u, flags.to_ulong());
|
||||
|
||||
Log::Comment(L"Reset bit 3 reference to false");
|
||||
flags.reset(Flags::Three);
|
||||
VERIFY_IS_FALSE(reference);
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
|
||||
Log::Comment(L"Flip bit 3 reference to true");
|
||||
reference.flip();
|
||||
VERIFY_IS_TRUE(reference);
|
||||
VERIFY_ARE_EQUAL(0b01000u, flags.to_ulong());
|
||||
|
||||
Log::Comment(L"Flip bit 3 reference back to false");
|
||||
reference.flip();
|
||||
VERIFY_IS_FALSE(reference);
|
||||
VERIFY_ARE_EQUAL(0b00000u, flags.to_ulong());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,6 +23,16 @@ set PATH=%PATH%%OPENCON%\dep\nuget;
|
|||
rem Run nuget restore so you can use vswhere
|
||||
nuget restore %OPENCON%\OpenConsole.sln -Verbosity quiet
|
||||
|
||||
:FIND_MSBUILD
|
||||
set MSBUILD=
|
||||
|
||||
rem GH#1313: If msbuild is already on the path, we don't need to look for it.
|
||||
for %%X in (msbuild.exe) do (set MSBUILD=%%~$PATH:X)
|
||||
if defined MSBUILD (
|
||||
echo Using MsBuild at %MSBUILD% which was already on the path.
|
||||
goto :FOUND_MSBUILD
|
||||
)
|
||||
|
||||
rem Find vswhere
|
||||
rem from https://github.com/microsoft/vs-setup-samples/blob/master/tools/vswhere.cmd
|
||||
for /f "usebackq delims=" %%I in (`dir /b /aD /o-N /s "%~dp0..\packages\vswhere*" 2^>nul`) do (
|
||||
|
@ -37,22 +47,23 @@ if not defined VSWHERE (
|
|||
)
|
||||
|
||||
rem Add path to MSBuild Binaries
|
||||
for /f "usebackq tokens=*" %%B in (`%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do (
|
||||
rem
|
||||
rem We're going to always prefer prerelease version of VS. This lets people who
|
||||
rem are using VS 2022 use that from the commandline over the 2019 version. This
|
||||
rem will use whatever the newest version of VS is, regardless if it's stable or
|
||||
rem not.
|
||||
rem
|
||||
for /f "usebackq tokens=*" %%B in (`%VSWHERE% -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do (
|
||||
set MSBUILD=%%B
|
||||
)
|
||||
|
||||
rem Try to find MSBuild in prerelease versions of MSVS
|
||||
if not defined MSBUILD (
|
||||
for /f "usebackq tokens=*" %%B in (`%VSWHERE% -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe 2^>nul`) do (
|
||||
set MSBUILD=%%B
|
||||
)
|
||||
)
|
||||
|
||||
if not defined MSBUILD (
|
||||
echo Could not find MsBuild on your machine. Please set the MSBUILD variable to the location of MSBuild.exe and run razzle again.
|
||||
goto :EXIT
|
||||
)
|
||||
|
||||
:FOUND_MSBUILD
|
||||
|
||||
set PATH=%PATH%%MSBUILD%\..;
|
||||
|
||||
if "%PROCESSOR_ARCHITECTURE%" == "AMD64" (
|
||||
|
|
Loading…
Reference in a new issue