Compare commits

...

21 commits

Author SHA1 Message Date
Leonard Hecker f2386de422
Improve performance and binary size of til::enumset (#11493)
This commit approximately doubles the performance of til::enumset
and reduces it's binary footprint by approximately 1kB.
Most of the binary size can be attributed to exception handling.

Unfortunately this commit removes assertions that the given values are less than
the number of bits in the `underlying_type`. However I believe this to be a good
trade-off as the tests previously only happened at runtime, while tests at
compile time would be highly preferable. Such tests are technically possible,
however MSVC fails to compile (valid) `static_assert`s containing
`static_cast`s over a parameter pack at the time of writing.
With future MSVC versions such checks can be added to this class.

This change was initially discussed in #10492, but was forgotten to
be considered before it was merged. Since the work was already done,
this commit re-introduces the optimization. It's free!

## PR Checklist
* [x] I work here.
* [x] Tests added/passed

## Validation Steps Performed
* Run `printf '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\\n'` in WSL
* A wild dotted line appears ✔️
2021-11-23 18:44:58 +00:00
Leonard Hecker 80f8383860
Fix AltGr not working in the settings UI (#11808)
Since the settings UI's input fields behave similarly to the terminal's input,
`TerminalPage::_KeyDownHandler` also needs to behave similarly to
`TermControl::_KeyHandler`. This commit copies all relevant code
over from the latter into the former, including the suppression
of AltGr keys for keychord/action handling.

## PR Checklist
* [x] Closes #11788
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Use a German keyboard layout
* Open 2 regular tabs and 1 settings tab and focus an input field
* AltGr+2 produces the character ² ✔️
* Ctrl+Alt+2 opens the second tab ✔️
2021-11-23 18:30:36 +00:00
James Holderness bb71179a24
Consolidate the color palette APIs (#11784)
This PR merges the default colors and cursor color into the main color
table, enabling us to simplify the `ConGetSet` and `ITerminalApi`
interfaces, with just two methods required for getting and setting any
form of color palette entry.

The is a follow-up to the color table standardization in #11602, and a
another small step towards de-duplicating `AdaptDispatch` and
`TerminalDispatch` for issue #3849. It should also make it easier to
support color queries (#3718) and a configurable bold color (#5682) in
the future.

On the conhost side, default colors could originally be either indexed
positions in the 16-color table, or separate standalone RGB values. With
the new system, the default colors will always be in the color table, so
we just need to track their index positions.

To make this work, those positions need to be calculated at startup
based on the loaded registry/shortcut settings, and updated when
settings are changed (this is handled in
`CalculateDefaultColorIndices`). But the plus side is that it's now much
easier to lookup the default color values for rendering.

For now the default colors in Windows Terminal use hardcoded positions,
because it doesn't need indexed default colors like conhost. But in the
future I'd like to extend the index handling to both terminals, so we
can eventually support the VT525 indexed color operations.

As for the cursor color, that was previously stored in the `Cursor`
class, which meant that it needed to be copied around in various places
where cursors were being instantiated. Now that it's managed separately
in the color table, a lot of that code is no longer required.

## Validation
Some of the unit test initialization code needed to be updated to setup
the color table and default index values as required for the new system.
There were also some adjustments needed to account for API changes, in
particular for methods that now take index values for the default colors
in place of COLORREFs. But for the most part, the essential behavior of
the tests remains unchanged.

I've also run a variety of manual tests looking at the legacy console
APIs as well as the various VT color sequences, and checking that
everything works as expected when color schemes are changed, both in
Windows Terminal and conhost, and in the latter case with both indexed
colors and RGB values.

Closes #11768
2021-11-23 18:28:55 +00:00
Mike Griese df06c54e70
Wrap these commands with quotes (#11807)
I'm pretty exactly following the diff from #917. These paths weren't wrapped in `"`s, so building the solution in a directory with a space in it would explode.

Closes #917.

Turns out, the diff provided by that user wasn't exactly right. I've tested building in a directory with spaces now, and this seems to work. 

Also caught a bug in the Generate Feature Flags script.
2021-11-23 17:01:59 +00:00
Mike Griese a98d18c030
Fix missing .xaml references (#11805)
I'm working on making the FastUpToDate check in Vs work for the Terminal project. This is one of a few PRs in this area.

FastUpToDate lets vs check quickly determine that it doesn't need to do anything for a given project. 

However, a few of our projects don't produce all the right artifacts, or check too many things, and this eventually causes the `wapproj` to rebuild, EVERY TIME YOU F5 in VS. 

This second PR deals with some projects MYSTERIOUSLY depending on the `.xaml` files from `Terminal.Control`, even when they by all accounts shouldn't. TerminalSettingsModel ISN'T EVEN A XAML project, so I have no idea why it thinks it needs these xaml files. The TerminalAppLib project thinking it needs them - makes more sense, but is still confusing. 
Below are my verbatim notes, which led to the solution in this PR. 


```
34>------ Up-To-Date check: Project: Microsoft.Terminal.Settings.Model.Lib, Configuration: Debug x64 ------
34>Project is not up-to-date: build output 'c:\users\migrie\dev\public\terminal\bin\x64\debug\microsoft.terminal.settings.model.lib\microsoft.terminal.control\searchboxcontrol.xaml' is missing
```

* Just copying the xaml files from `bin\x64\debug\microsoft.terminal.control\microsoft.terminal.control\*.xaml` to `bin\x64\debug\microsoft.terminal.settings.model.lib\microsoft.terminal.control` seemed to fix this.
* the .xbfs were already there
* It's very unclear why these were ever needed? They aren't used in the build for `Microsoft.Terminal.Settings.Model.Lib`. They aren't copied as a part of the build either - no .xaml files are copied at all in fact
* [ ] Does TSE have these .xamls in it's output?
* UPDATE: checking out main, and building again - ran into this again. WHY??
* Cleaned again, then built TerminalApp.vcxproj. File is no longer needed? nothing makes sense.


* `obj\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsof.CA5CAD1A.tlog\Microsoft.Terminal.Settings.Model.Lib.write.1u.tlog`:
```
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\SearchBoxControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TermControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TSFInputControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.UI.Xaml\Assets\NoiseAsset_256X256_PNG.png
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\SearchBoxControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TermControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TSFInputControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\SearchBoxControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TermControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TSFInputControl.xbf
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\SearchBoxControl.xaml
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TermControl.xaml
C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TSFInputControl.xaml
```

From the build:
```
18>Target _CopyOutOfDateSourceItemsToOutputDirectory:
18>  Skipping target "_CopyOutOfDateSourceItemsToOutputDirectory" because all output files are up-to-date with respect to the input files.
18>  Input files:
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Control\Microsoft.Terminal.Control\SearchBoxControl.xbf
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Control\Microsoft.Terminal.Control\TermControl.xbf
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Control\Microsoft.Terminal.Control\TSFInputControl.xbf
18>      C:\Users\migrie\dev\public\terminal\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-x64\native\Microsoft.UI.Xaml\Assets\NoiseAsset_256X256_PNG.png
18>  Output files:
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\SearchBoxControl.xbf
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TermControl.xbf
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.Terminal.Control\TSFInputControl.xbf
18>      C:\Users\migrie\dev\public\terminal\bin\x64\Debug\Microsoft.Terminal.Settings.Model.Lib\Microsoft.UI.Xaml\Assets\NoiseAsset_256X256_PNG.png
```

* Hmm, `21>Project is not up-to-date: build output 'c:\users\migrie\dev\public\terminal\bin\x64\debug\terminalapplib\microsoft.terminal.control\searchboxcontrol.xaml' is missing`
  as well.
2021-11-23 16:53:05 +00:00
Mike Griese dc01926e3e
Add some details about working on assigned issues (#11802)
That's what the original purpose of #865 was, but I went ahead and added some additiona text, now that we've got more of a flow for github figured out.

Closes #865
2021-11-23 15:21:42 +00:00
Mike Griese 6ad848e158
Prefer Preview VS builds always; use any existing msbuild if it's on the path (#11803)
If msbuild is already on the path, we don't need to look for it.

Also,
> I know what I did. I installed VS 2022, which is a prerelease VS install. `tools\razzle` prefers the stable builds. I think I'm gonna remove that.

* [x] Closes #1313
* [x] Closes #11446
2021-11-23 06:35:21 -06:00
Mike Griese ea456cf121
Fix for missing CopyComplete files in TerminalConnection.vcxproj (#11804)
I'm working on making the FastUpToDate check in Vs work for the Terminal project. This is one of a few PRs in this area.

FastUpToDate lets vs check quickly determine that it doesn't need to do anything for a given project. 

However, a few of our projects don't produce all the right artifacts, or check too many things, and this eventually causes the `wapproj` to rebuild, EVERY TIME YOU F5 in VS. 

This first PR deals with the `.copycomplete` file in `obj\x64\debug\terminalconnection\`. Below are my verbatim notes, which led to the solution in this PR. 








### Problem 1 
* There were missing `.copycomplete` files across the repo. 
  ```
  obj\x64\debug\microsoft.terminal.settings.model.lib\microsoft.terminal.settings.modellib.vcxproj.copycomplete
  obj\x64\debug\microsoft.terminal.settings.model\microsoft.terminal.settings.model.vcxproj.copycomplete
  obj\x64\debug\terminalapplib\terminalapplib.vcxproj.copycomplete
  obj\x64\debug\terminalapp\terminalapp.vcxproj.copycomplete
  obj\x64\debug\terminalconnection\terminalconnection.vcxproj.copycomplete
  ```
  - just making empty files there seemed good enough. 
  - Might be because the CopyLocal target was already there, but the task didn't ever run to create that file? Weird.
* UPDATE: checking out main, and building again - the `.copycomplete`s are gone. So that's something that can be improved.
* The only place I could find a reference was in `"obj\x64\Debug\TerminalConnection\TerminalConnection.vcxproj.FileListAbsolute.txt"`, which will get updated if you remove the line from that file (but no one seemingly writes it or mentiones it in the log)
* Deleting `bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll` then building the project did copy the file, but it didn't touch the copycomplete. Weird.
* Why does
  - `TerminalConnection` think it needs this
  - `Microsoft.Terminal.Settings.Model.Lib` have one
  - `Microsoft.Terminal.Control*` **NOT** have one


* This file is a [`@(CopyUpToDateMarker)`](https://github.com/dotnet/msbuild/blob/main/src/Tasks/Microsoft.Common.CurrentVersion.targets#L392)
* The target [`_CopyFilesMarkedCopyLocal`](https://github.com/dotnet/msbuild/blob/main/src/Tasks/Microsoft.Common.CurrentVersion.targets#L4795) touches `@(CopyUpToDateMarker)`, when:
  - `"'@(ReferencesCopiedInThisBuild)' != ''` and
  - `'$(WroteAtLeastOneFile)' == 'true'"`

* In out build output:
```
6>Target _CopyFilesMarkedCopyLocal:
6>  Using "Copy" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
6>  Task "Copy"
6>    Did not copy from file "C:\Users\migrie\dev\public\terminal\bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll" to file "C:\Users\migrie\dev\public\terminal\bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll" because the "SkipUnchangedFiles" parameter was set to "true" in the project and the files' sizes and timestamps match.
6>  Done executing task "Copy".
6>  Task "Touch" skipped, due to false condition; ('@(ReferencesCopiedInThisBuild)' != '' and '$(WroteAtLeastOneFile)' == 'true') was evaluated as ('C:\Users\migrie\dev\public\terminal\bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll' != '' and 'False' == 'true').
```
  - So `WroteAtLeastOneFile` should be true, when it's currently false. That _looks_ like it's set to true when the file does get copied, wheich did't happen because the copy was skipped.
  - WAIT LOOK AT THAT MESSAGE. "Did not copy from file "
    `"C:\Users\migrie\dev\public\terminal\bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll"`  to file
    `"C:\Users\migrie\dev\public\terminal\bin\x64\Debug\TerminalConnection\cpprest142_2_10d.dll"`
    THESE ARE THE SAME FILE.
    `@(ReferenceCopyLocalPaths)` is filled with the file already?!
- The Target `AppLocalFromInstalled` is the only other thing that references `cpprest142_2_10d.dll`.
- Even if you delete the `cpprest142_2_10d.dll`, then `_CopyFilesMarkedCopyLocal` still evaluates the Touch condition as false, and doesn't touch it.
- the `deployBinary()` function in `packages\vcpkg-cpprestsdk.2.10.14\scripts\buildsystems\msbuild\applocal.ps1` does the actual job of copying the file. It copies it outside of MsBuild, which prevents MsBuild from copying it, and now MsBuild thinks it shouldn't write the `.copycomplete` file itself.
2021-11-23 11:51:45 +00:00
Mike Griese 442432ea15
Fixes the wapproj fast-up-to-date check (#11806)
I'm working on making the FastUpToDate check in Vs work for the Terminal project. This is one of a few PRs in this area.

FastUpToDate lets vs check quickly determine that it doesn't need to do anything for a given project. 

However, a few of our projects don't produce all the right artifacts, or check too many things, and this eventually causes the `wapproj` to rebuild, EVERY TIME YOU F5 in VS. 

This third PR deals with the Actual fast up to date check for the CascadiaPackage.wapproj. When #11804, #11805 and this PR are all merged, you should be able to just F5 the Terminal in VS, and then change NOTHING, and F5 it again, without doing a build at all. 




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.

### teams chat where we figured this out

[3:38 PM] Dustin Howett
however, that's not the only thing that "GetTargetPath" checks.

[3:38 PM] Dustin Howett
oh yeah more info: wapproj calls GetTargetPath on all projects it references

[3:38 PM] Dustin Howett
when it calls GTP on WindowsTerminal.vcxproj it is getting back a winmd (!)


[3:39 PM] Dustin Howett
here's the magic

[3:39 PM] Dustin Howett
![image](https://user-images.githubusercontent.com/18356694/142945542-74734836-20d8-4f50-bf3a-be4e1170ae13.png)


[3:39 PM] Dustin Howett
it checks if any Link items specify GenerateWindowsMetadata

![image](https://user-images.githubusercontent.com/18356694/142945593-fd232243-0175-4653-8c34-cdc364a16031.png)
2021-11-23 11:22:56 +00:00
Leonard Hecker fc85bdf314
Upgrade to Windows SDK 22000 (#11728)
Upgrades our SDK from 19041 (Windows 10 20H1) to 22000 (Windows 11 RTM).
The newer SDK is  more compatible with /Zc:preprocessor
and will allow us to use newer Windows 11 APIs directly.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* Compiles ✔️
* Runs ✔️
2021-11-18 18:08:26 +00:00
Leonard Hecker a68b0d4f08
Introduce new TIL string helpers, teach older ones to use wmemcmp (#11725)
til::equals:
At the time of writing wmemcmp() is not an intrinsic for MSVC,
but the STL uses it to implement wide string comparisons.
This produces 3x the assembly _per_ comparison and increases
runtime by 2-3x for strings of medium length (16 characters)
and 5x or more for long strings (128 characters or more).
See: https://github.com/microsoft/STL/issues/2289

Additionally a number of case insensitive, locale unaware
helpers for prefix/suffix comparisons are introduced.
2021-11-17 23:42:40 +00:00
James Holderness 6742965bb8
Disable the acceptance of C1 control codes by default (#11690)
There are some code pages with "unmapped" code points in the C1 range,
which results in them being translated into Unicode C1 control codes,
even though that is not their intended use. To avoid having these
characters triggering unintentional escape sequences, this PR now
disables C1 controls by default.

Switching to ISO-2022 encoding will re-enable them, though, since that
is the most likely scenario in which they would be required. They can
also be explicitly enabled, even in UTF-8 mode, with the `DECAC1` escape
sequence.

What I've done is add a new mode to the `StateMachine` class that
controls whether C1 code points are interpreted as control characters or
not. When disabled, these code points are simply dropped from the
output, similar to the way a `NUL` is interpreted.

This isn't exactly the way they were handled in the v1 console (which I
think replaces them with the font _notdef_ glyph), but it matches the
XTerm behavior, which seems more appropriate considering this is in VT
mode. And it's worth noting that Windows Explorer seems to work the same
way.

As mentioned above, the mode can be enabled by designating the ISO-2022
coding system with a `DOCS` sequence, and it will be disabled again when
UTF-8 is designated. You can also enable it explicitly with a `DECAC1`
sequence (originally this was actually a DEC printer sequence, but it
doesn't seem unreasonable to use it in a terminal).

I've also extended the operations that save and restore "cursor state"
(e.g. `DECSC` and `DECRC`) to include the state of the C1 parser mode,
since it's closely tied to the code page and character sets which are
also saved there. Similarly, when a `DECSTR` sequence resets the code
page and character sets, I've now made it reset the C1 mode as well.

I should note that the new `StateMachine` mode is controlled via a
generic `SetParserMode` method (with a matching API in the `ConGetSet`
interface) to allow for easier addition of other modes in the future.
And I've reimplemented the existing ANSI/VT52 mode in terms of these
generic methods instead of it having to have its own separate APIs.

## Validation Steps Performed

Some of the unit tests for OSC sequences were using a C1 `0x9C` for the
string terminator, which doesn't work by default anymore. Since that's
not a good practice anyway, I thought it best to change those to a
standard 7-bit terminator. However, in tests that were explicitly
validating the C1 controls, I've just enabled the C1 parser mode at the
start of the tests in order to get them working again.

There were also some ANSI mode adapter tests that had to be updated to
account for the fact that it has now been reimplemented in terms of the
`SetParserMode` API.

I've added a new state machine test to validate the changes in behavior
when the C1 parser mode is enabled or disabled. And I've added an
adapter test to verify that the `DesignateCodingSystems` and
`AcceptC1Controls` methods toggle the C1 parser mode as expected.

I've manually verified the test cases in #10069 and #10310 to confirm
that they're no longer triggering control sequences by default.
Although, as I explained above, the C1 code points are completely
dropped from the output rather than displayed as _notdef_ glyphs. I
think this is a reasonable compromise though.

Closes #10069
Closes #10310
2021-11-17 23:40:31 +00:00
Leonard Hecker 131f5d2b32
Use nearby fonts for font fallback (#11764)
This commit is a minimal fix in order to pass the
`IDWriteFontCollection` we create out of .ttf files residing next to our
binaries to the `IDWriteFontFallback::MapCharacters` call. The
`IDWriteTextFormat` is used in order to carry the font collection over
into `CustomTextLayout`.

## Validation
* Put `JetBrainsMono-Regular.ttf` into the binary output directory
* Modify `HKCU:\Console\*\FaceName`  to `JetBrains Mono`
* Launch OpenConsole.exe
* OpenConsole uses JetBrains Mono ✔️

Closes #11032
Closes #11648
2021-11-16 23:22:02 +00:00
Sergey 7bfaad4592
Fix missing window border when use "win+arrow down" in fullscreen mode in Conhost (#11692)
Window exits out of fullscreen if it receives SC_RESTORE

Closes #10607
2021-11-16 16:14:54 +00:00
Mike Griese c455418659
Separate terminal version and Windows version in issue template (#11528) 2021-11-16 07:24:42 -06:00
Mike Griese c79334ffbb
Add a file for storing elevated-only state (#11222)
## Summary of the Pull Request

This creates an `elevated-state.json` that lives in `%LOCALAPPDATA%` next to `state.json`, that's only writable when elevated. It doesn't _use_ this file for anything, it just puts the framework down for use later.

It's _just like `ApplicationState`_. We'll use it the same way. 

It's readable when unelevated, which is nice, but not writable. If you're dumb and try to write to the file when unelevated, it'll just silently do nothing.

If we try opening the file and find out the permissions are different, we'll _blow the file away entirely_. This is to prevent someone from renaming the original file (which they can do unelevated), then slapping a new file that's writable by them down in it's place. 

## References
* We're going to use this in #11096, but these PRs need to be broken up.

## PR Checklist
* [x] Closes nothing
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - maybe? not sure we have docs on `state.json` at all yet

## Validation Steps Performed
I've played with this much more in `dev/migrie/f/non-terminal-content-elevation-warning`

###### followed by #11308, #11310
2021-11-13 01:58:43 +01:00
Leonard Hecker 2353349fe5
Introduce AtlasEngine - A new text rendering prototype (#11623)
This commit introduces "AtlasEngine", a new text renderer based on DxEngine.
But unlike it, DirectWrite and Direct2D are only used to rasterize glyphs.
Blending and placing these glyphs into the target view is being done using
Direct3D and a simple HLSL shader. Since this new renderer more aggressively
assumes that the text is monospace, it simplifies the implementation:
The viewport is divided into cells, and its data is stored as a simple matrix.
Modifications to this matrix involve only simple pointer arithmetic and is easy
to understand. But just like with DxEngine however, DirectWrite
related code remains extremely complex and hard to understand.

Supported features:
* Basic text rendering with grayscale AA
* Foreground and background colors
* Emojis, including zero width joiners
* Underline, dotted underline, strikethrough
* Custom font axes and features
* Selections
* All cursor styles
* Full alpha support for all colors
* _Should_ work with Windows 7

Unsupported features:
* A more conservative GPU memory usage
  The backing texture atlas for glyphs is grow-only and will not shrink.
  After 256MB of memory is used up (~20k glyphs) text output
  will be broken until the renderer is restarted.
* ClearType
* Remaining gridlines (left, right, top, bottom, double underline)
* Hyperlinks don't get full underlines if hovered in WT
* Softfonts
* Non-default line renditions

Performance:
* Runs at up to native display refresh rate
  Unfortunately the frame rate often drops below refresh rate, due us
  fighting over the buffer lock with other parts of the application.
* CPU consumption is up to halved compared to DxEngine
  AtlasEngine is still highly unoptimized. Glyph hashing
  consumes up to a third of the current CPU time.
* No regressions in WT performance
  VT parsing and related buffer management takes up most of the CPU time (~85%),
  due to which the AtlasEngine can't show any further improvements.
* ~2x improvement in raw text throughput in OpenConsole
  compared to DxEngine running at 144 FPS
* ≥10x improvement in colored VT output in WT/OpenConsole
  compared to DxEngine running at 144 FPS
2021-11-13 00:10:06 +00:00
Dustin Howett f6965aeb53 Merge remote-tracking branch 'openconsole/inbox' 2021-11-10 16:30:41 -06:00
Matt Peterson d5974f4c91
Automatically convert paths dropped on WSL instances (#11625)
Drag and drop does not work for WSL because paths are pasted as windows
paths having incorrect path separator and path root.  This PR adds code
to correct the path in TerminalControl before pasting to WSL terminals.

One problem with this approach is that it assumes the default WSL
automount root of "/mnt". It would be possible to add a setting like
"WslDragAndDropMountRoot"... but I decided it if someone wants to change
automount location it would be simple enough just to create the "/mnt"
symlink in WSL.

## Validation
Couldn't find an obvious place to add a test.  Manually tested
cut-n-paste from following paths:
- "c:\"
- "c:\subdir"
- "c:\subdir\subdir"
- "\\wsl.localhost\<distro>"
- \\wsl.localhost\<distro>\subdir"

Closes #331
2021-11-10 21:19:52 +00:00
Dustin Howett 3fc82c2d4b Migrate OSS up to 305255c65 2021-11-10 15:07:17 -06:00
Leonard Hecker 305255c658
Fix a conhost binary size regression due to fmt (#11727)
6140fd9 causes a binary size regression in conhost.
This PR fixes most if not all of the regression, by replacing `FMT_STRING`
with `FMT_COMPILE` allowing us to drop most of the formatters built
into fmt during linking (for instance floating point formatters).

Additionally `std::wstring` was replaced with `fmt::basic_memory_buffer`
in the same vein as was done for VtEngine. Stack is
cheap and this prevents any unnecessary allocations.

## PR Checklist
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
* vttest 11.2.5.3.6.7 and .8 (DECSTBM and SGR) complete successfully 
2021-11-10 21:03:47 +00:00
167 changed files with 5881 additions and 1666 deletions

View file

@ -10,14 +10,21 @@ body:
- type: input
attributes:
label: Windows Terminal version (or Windows build number)
placeholder: "10.0.19042.0, 1.7.3651.0"
label: Windows Terminal version
placeholder: "1.7.3651.0"
description: |
If you are reporting an issue in Windows Terminal, you can find the version in the about dialog.
If you are reporting an issue with the Windows Console, please run `ver` or `[Environment]::OSVersion`.
You can find the version in the about dialog, or by running `wt -v` at the commandline.
validations:
required: true
required: false
- type: input
attributes:
label: Windows build number
placeholder: "10.0.19042.0"
description: |
Please run `ver` or `[Environment]::OSVersion`.
validations:
required: false
- type: textarea
attributes:

View file

@ -1,12 +1,14 @@
admins
apc
Apc
bsd
calt
ccmp
changelog
cybersecurity
Apc
clickable
clig
copyable
cybersecurity
dalet
dcs
Dcs
@ -30,20 +32,22 @@ hyperlink
hyperlinking
hyperlinks
img
inlined
It'd
kje
liga
lje
locl
lorem
Llast
Lmid
locl
lorem
Lorigin
maxed
mkmk
mnt
mru
noreply
nje
noreply
ogonek
ok'd
overlined

View file

@ -1,5 +1,7 @@
ACCEPTFILES
ACCESSDENIED
acl
aclapi
alignas
alignof
APPLYTOSUBMENUS
@ -21,6 +23,7 @@ commandlinetoargv
cstdint
CXICON
CYICON
Dacl
dataobject
dcomp
DERR
@ -117,15 +120,19 @@ OSVERSIONINFOEXW
otms
OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PEXPLICIT
PICKFOLDERS
pmr
ptstr
rcx
REGCLS
RETURNCMD
rfind
roundf
RSHIFT
SACL
schandle
semver
serializer
@ -162,6 +169,7 @@ toupper
TTask
TVal
UChar
UFIELD
ULARGE
UPDATEINIFILE
userenv

View file

@ -9,6 +9,7 @@ Diviness
dsafa
duhowett
ekg
eryksun
ethanschoonover
Firefox
Gatta

View file

@ -61,6 +61,7 @@ SUMS$
^src/host/runft\.bat$
^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/adapter/ut_adapter/run\.bat$
^src/terminal/parser/delfuzzpayload\.bat$

View file

@ -508,6 +508,7 @@ dealloc
Debian
debolden
debugtype
DECAC
DECALN
DECANM
DECAUPSS

View file

@ -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)

View file

@ -17,7 +17,7 @@
"Microsoft.Net.Component.4.5.TargetingPack",
"Microsoft.VisualStudio.Component.DiagnosticTools",
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
"Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Microsoft.VisualStudio.Component.Windows10SDK.22000",
"Microsoft.VisualStudio.ComponentGroup.UWP.Support",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",

View file

@ -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.

View file

@ -400,6 +400,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererAtlas", "src\renderer\atlas\atlas.vcxproj", "{8222900C-8B6C-452A-91AC-BE95DB04B95F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU
@ -3339,6 +3341,46 @@ Global
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.ActiveCfg = Release|Win32
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.ActiveCfg = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.Build.0 = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.Build.0 = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.Build.0 = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.Build.0 = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|Any CPU.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -3438,6 +3480,7 @@ Global
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {05500DEF-2294-41E3-AF9A-24E580B82836}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}

View file

@ -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 &quot;$(SolutionDir)\tools\Generate-FeatureStagingHeader.ps1&quot; -Path &quot;%(FeatureFlagFile.FullPath)&quot; -Branding $(_WTBrandingName)"
Command="powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy ByPass -Command &quot;&amp;&apos;$(SolutionDir)\tools\Generate-FeatureStagingHeader.ps1&apos; -Path &apos;%(FeatureFlagFile.FullPath)&apos; -Branding $(_WTBrandingName)&quot;"
ConsoleToMsBuild="true"
StandardOutputImportance="low">
<Output TaskParameter="ConsoleOutput" ItemName="_FeatureFlagFileLines" />

View file

@ -22,7 +22,7 @@ Param(
[Parameter(HelpMessage="Path to makeappx.exe")]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\MakeAppx.exe"
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86\MakeAppx.exe"
)
If ($null -Eq (Get-Item $MakeAppxPath -EA:SilentlyContinue)) {

View file

@ -8,7 +8,7 @@ Param(
[Parameter(HelpMessage="Path to Windows Kit")]
[ValidateScript({Test-Path $_ -Type Leaf})]
[string]
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0"
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0"
)
$ErrorActionPreference = "Stop"

View file

@ -380,7 +380,7 @@ Here's the AppxManifest we're using:
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
</Dependencies>
@ -517,7 +517,7 @@ This is because of a few key lines we already put in the appxmanifest:
```xml
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
</Dependencies>

View file

@ -23,7 +23,7 @@
<ProjectGuid>{96274800-9574-423E-892A-909FBE2AC8BE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>EchoCon</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -163,4 +163,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -27,7 +27,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -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')" />

View file

@ -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.

View file

@ -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;

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -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;
};

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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">

View file

@ -26,7 +26,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -27,7 +27,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -27,7 +27,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -28,7 +28,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22000.0" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
</Dependencies>

View file

@ -9,7 +9,7 @@
<uap:SupportedUsers>multiple</uap:SupportedUsers>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />

View file

@ -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

View file

@ -29,6 +29,9 @@
<ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj">
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)src\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)src\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference>

View file

@ -12,6 +12,8 @@
#include <WtExeUtils.h>
#include <wil/token_helpers.h >
#include "../../types/inc/utils.hpp"
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::UI::Xaml;
@ -131,38 +133,6 @@ static Documents::Run _BuildErrorRun(const winrt::hstring& text, const ResourceD
return textRun;
}
// Method Description:
// - Returns whether the user is either a member of the Administrators group or
// is currently elevated.
// - This will return **FALSE** if the user has UAC disabled entirely, because
// there's no separation of power between the user and an admin in that case.
// Return Value:
// - true if the user is an administrator
static bool _isUserAdmin() noexcept
try
{
wil::unique_handle processToken{ GetCurrentProcessToken() };
const auto elevationType = wil::get_token_information<TOKEN_ELEVATION_TYPE>(processToken.get());
const auto elevationState = wil::get_token_information<TOKEN_ELEVATION>(processToken.get());
if (elevationType == TokenElevationTypeDefault && elevationState.TokenIsElevated)
{
// In this case, the user has UAC entirely disabled. This is sort of
// weird, we treat this like the user isn't an admin at all. There's no
// separation of powers, so the things we normally want to gate on
// "having special powers" doesn't apply.
//
// See GH#7754, GH#11096
return false;
}
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return false;
}
namespace winrt::TerminalApp::implementation
{
// Function Description:
@ -214,7 +184,7 @@ namespace winrt::TerminalApp::implementation
// The TerminalPage has to be constructed during our construction, to
// make sure that there's a terminal page for callers of
// SetTitleBarContent
_isElevated = _isUserAdmin();
_isElevated = ::Microsoft::Console::Utils::IsElevated();
_root = winrt::make_self<TerminalPage>();
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
@ -910,8 +880,6 @@ namespace winrt::TerminalApp::implementation
void AppLogic::_RegisterSettingsChange()
{
const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } };
const std::filesystem::path statePath{ std::wstring_view{ ApplicationState::SharedInstance().FilePath() } };
_reader.create(
settingsPath.parent_path().c_str(),
false,
@ -920,14 +888,29 @@ namespace winrt::TerminalApp::implementation
// editors, who will write a temp file, then rename it to be the
// actual file you wrote. So listen for that too.
wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime,
[this, settingsBasename = settingsPath.filename(), stateBasename = statePath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
const auto modifiedBasename = std::filesystem::path{ fileModified }.filename();
[this, settingsBasename = settingsPath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
// DO NOT create a static reference to ApplicationState::SharedInstance here.
//
// ApplicationState::SharedInstance already caches its own
// static ref. If _we_ keep a static ref to the member in
// AppState, then our reference will keep ApplicationState alive
// after the `ActionToStringMap` gets cleaned up. Then, when we
// try to persist the actions in the window state, we won't be
// able to. We'll try to look up the action and the map just
// won't exist. We'll explode, even though the Terminal is
// tearing down anyways. So we'll just die, but still invoke
// WinDBG's post-mortem debugger, who won't be able to attach to
// the process that's already exiting.
//
// So DON'T ~give a mouse a cookie~ take a static ref here.
const winrt::hstring modifiedBasename{ std::filesystem::path{ fileModified }.filename().c_str() };
if (modifiedBasename == settingsBasename)
{
_reloadSettings->Run();
}
else if (modifiedBasename == stateBasename)
else if (ApplicationState::SharedInstance().IsStatePath(modifiedBasename))
{
_reloadState();
}

View file

@ -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

View file

@ -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 });
@ -300,10 +300,7 @@ namespace winrt::TerminalApp::implementation
// - true if the ApplicationState should be used.
bool TerminalPage::ShouldUsePersistedLayout(CascadiaSettings& settings) const
{
// GH#5000 Until there is a separate state file for elevated sessions we should just not
// save at all while in an elevated window.
return Feature_PersistedWindowLayout::IsEnabled() &&
!IsElevated() &&
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout;
}
@ -1041,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)
{
}
}

View file

@ -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();

View file

@ -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>

View file

@ -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>

View file

@ -3,16 +3,18 @@
#include "pch.h"
#include "ControlCore.h"
#include <argb.h>
#include <DefaultSettings.h>
#include <unicode.hpp>
#include <Utf16Parser.hpp>
#include <Utils.h>
#include <WinUser.h>
#include <LibraryResources.h>
#include "EventArgs.h"
#include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp"
#include "../../buffer/out/search.h"
#include "../../renderer/atlas/AtlasEngine.h"
#include "../../renderer/dx/DxRenderer.hpp"
#include "ControlCore.g.cpp"
@ -202,6 +204,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const double actualHeight,
const double compositionScale)
{
assert(_settings);
_panelWidth = actualWidth;
_panelHeight = actualHeight;
_compositionScale = compositionScale;
@ -222,10 +226,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false;
}
// Set up the DX Engine
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
_renderer->AddRenderEngine(dxEngine.get());
_renderEngine = std::move(dxEngine);
if (Feature_AtlasEngine::IsEnabled() && _settings.UseAtlasEngine())
{
_renderEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
}
else
{
_renderEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
}
_renderer->AddRenderEngine(_renderEngine.get());
// Initialize our font with the renderer
// We don't have to care about DPI. We'll get a change message immediately if it's not 96
@ -271,11 +281,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
_updateAntiAliasingMode(_renderEngine.get());
_updateAntiAliasingMode();
// GH#5098: Inform the engine of the opacity of the default text background.
// GH#11315: Always do this, even if they don't have acrylic on.
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
const auto backgroundIsOpaque = _settings.Opacity() == 1.0 && _settings.BackgroundImage().empty();
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
THROW_IF_FAILED(_renderEngine->Enable());
@ -616,7 +627,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
_updateAntiAliasingMode(_renderEngine.get());
_updateAntiAliasingMode();
// Refresh our font with the renderer
const auto actualFontOldSize = _actualFont.GetSize();
@ -650,22 +661,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::_updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine)
void ControlCore::_updateAntiAliasingMode()
{
// Update DxEngine's AntialiasingMode
D2D1_TEXT_ANTIALIAS_MODE mode;
switch (_settings.AntialiasingMode())
{
case TextAntialiasingMode::Cleartype:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
break;
case TextAntialiasingMode::Aliased:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
break;
case TextAntialiasingMode::Grayscale:
default:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
break;
}
_renderEngine->SetAntialiasingMode(mode);
}
// Method Description:
@ -1076,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:
@ -1296,7 +1309,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_renderEngine)
{
auto lock = _terminal->LockForWriting();
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(opacity));
const auto backgroundIsOpaque = opacity == 1.0 && _settings.BackgroundImage().empty();
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
}
}

View file

@ -15,11 +15,8 @@
#pragma once
#include "EventArgs.h"
#include "ControlCore.g.h"
#include "../../renderer/base/Renderer.hpp"
#include "../../renderer/dx/DxRenderer.hpp"
#include "../../renderer/uia/UiaRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../buffer/out/search.h"
#include "cppwinrt_utils.h"
@ -188,7 +185,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// As _renderer has a dependency on _renderEngine (through a raw pointer)
// we must ensure the _renderer is deallocated first.
// (C++ class members are destroyed in reverse order.)
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine{ nullptr };
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
IControlSettings _settings{ nullptr };
@ -248,7 +245,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma endregion
void _raiseReadOnlyWarning();
void _updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine);
void _updateAntiAliasingMode();
void _connectionOutputHandler(const hstring& hstr);
void _updateHoveredCell(const std::optional<til::point> terminalPosition);

View file

@ -22,6 +22,7 @@
#include "cppwinrt_utils.h"
#include "ControlCore.h"
#include "../../renderer/uia/UiaRenderer.hpp"
namespace ControlUnitTests
{

View file

@ -27,10 +27,11 @@ namespace Microsoft.Terminal.Control
interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings, Microsoft.Terminal.Control.IControlAppearance
{
String ProfileName;
String ProfileSource;
Boolean UseAcrylic;
ScrollbarState ScrollState;
Boolean UseAtlasEngine;
String FontFace;
Int32 FontSize;
Windows.UI.Text.FontWeight FontWeight;

View file

@ -3,17 +3,16 @@
#include "pch.h"
#include "TermControl.h"
#include <argb.h>
#include <DefaultSettings.h>
#include <unicode.hpp>
#include <Utf16Parser.hpp>
#include <Utils.h>
#include <LibraryResources.h>
#include "TermControlAutomationPeer.h"
#include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp"
#include "../../renderer/atlas/AtlasEngine.h"
#include "TermControl.g.cpp"
#include "TermControlAutomationPeer.h"
using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Console::VirtualTerminal;
@ -774,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);
}
@ -874,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.
@ -907,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
@ -989,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()))
@ -1828,13 +1830,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const winrt::Windows::Foundation::Size initialSize{ cols, rows };
return GetProposedDimensions(initialSize,
settings.FontSize(),
settings.FontWeight(),
settings.FontFace(),
settings.ScrollState(),
settings.Padding(),
dpi);
return GetProposedDimensions(settings, dpi, initialSize);
}
// Function Description:
@ -1855,16 +1851,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// caller knows what monitor the control is about to appear on.
// Return Value:
// - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars,
const int32_t& fontHeight,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi)
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars)
{
const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width);
const auto rows = ::base::saturated_cast<int>(initialSizeInChars.Height);
const auto fontSize = settings.FontSize();
const auto fontWeight = settings.FontWeight();
const auto fontFace = settings.FontFace();
const auto scrollState = settings.ScrollState();
const auto padding = settings.Padding();
// Initialize our font information.
// The font width doesn't terribly matter, we'll only be using the
@ -1873,28 +1868,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// The family is only used to determine if the font is truetype or
// not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all.
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontHeight) }, CP_UTF8, false };
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontSize) }, CP_UTF8, false };
FontInfoDesired desiredFont = { actualFont };
// Create a DX engine and initialize it with our font and DPI. We'll
// then use it to measure how much space the requested rows and columns
// will take up.
// TODO: MSFT:21254947 - use a static function to do this instead of
// instantiating a DxEngine
// instantiating a DxEngine/AtlasEngine.
// GH#10211 - UNDER NO CIRCUMSTANCE should this fail. If it does, the
// whole app will crash instantaneously on launch, which is no good.
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
LOG_IF_FAILED(dxEngine->UpdateDpi(dpi));
LOG_IF_FAILED(dxEngine->UpdateFont(desiredFont, actualFont));
double scale;
if (Feature_AtlasEngine::IsEnabled() && settings.UseAtlasEngine())
{
auto engine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
LOG_IF_FAILED(engine->UpdateDpi(dpi));
LOG_IF_FAILED(engine->UpdateFont(desiredFont, actualFont));
scale = engine->GetScaling();
}
else
{
auto engine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
LOG_IF_FAILED(engine->UpdateDpi(dpi));
LOG_IF_FAILED(engine->UpdateFont(desiredFont, actualFont));
scale = engine->GetScaling();
}
const auto scale = dxEngine->GetScaling();
const auto fontSize = actualFont.GetSize();
const auto actualFontSize = actualFont.GetSize();
// UWP XAML scrollbars aren't guaranteed to be the same size as the
// ComCtl scrollbars, but it's certainly close enough.
const auto scrollbarSize = GetSystemMetricsForDpi(SM_CXVSCROLL, dpi);
double width = cols * fontSize.X;
double width = cols * actualFontSize.X;
// Reserve additional space if scrollbar is intended to be visible
if (scrollState == ScrollbarState::Visible)
@ -1902,7 +1908,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
width += scrollbarSize;
}
double height = rows * fontSize.Y;
double height = rows * actualFontSize.Y;
const auto thickness = ParseThicknessFromPadding(padding);
// GH#2061 - make sure to account for the size the padding _will be_ scaled to
width += scale * (thickness.Left + thickness.Right);
@ -1962,13 +1968,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const winrt::Windows::Foundation::Size minSize{ 1, 1 };
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
return GetProposedDimensions(minSize,
_settings.FontSize(),
_settings.FontWeight(),
_settings.FontFace(),
_settings.ScrollState(),
_settings.Padding(),
dpi);
return GetProposedDimensions(_settings, dpi, minSize);
}
}
@ -2063,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
@ -2271,6 +2271,42 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
std::wstring fullPath{ item.Path() };
// Fix path for WSL
if (_settings.ProfileSource() == L"Windows.Terminal.Wsl")
{
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
if (fullPath.size() >= 2 && fullPath.at(1) == L':')
{
// C:/foo/bar -> Cc/foo/bar
fullPath.at(1) = til::tolower_ascii(fullPath.at(0));
// Cc/foo/bar -> /mnt/c/foo/bar
fullPath.replace(0, 1, L"/mnt/");
}
else
{
static constexpr std::wstring_view wslPathPrefixes[] = { L"//wsl.localhost/", L"//wsl$/" };
for (auto prefix : wslPathPrefixes)
{
if (til::starts_with(fullPath, prefix))
{
if (const auto idx = fullPath.find(L'/', prefix.size()); idx != std::wstring::npos)
{
// //wsl.localhost/Ubuntu-18.04/foo/bar -> /foo/bar
fullPath.erase(0, idx);
}
else
{
// //wsl.localhost/Ubuntu-18.04 -> /
fullPath = L"/";
}
break;
}
}
}
}
const auto containsSpaces = std::find(fullPath.begin(),
fullPath.end(),
L' ') != fullPath.end();
@ -2283,6 +2319,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
allPaths += fullPath;
}
_core.PasteText(winrt::hstring{ allPaths });
}
}

View file

@ -92,13 +92,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void Settings(IControlSettings newSettings);
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi);
static Windows::Foundation::Size GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars,
const int32_t& fontSize,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi);
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
void BellLightOn();
@ -251,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);

View file

@ -147,6 +147,7 @@
<ProjectReference Include="..\..\types\lib\types.vcxproj" />
<ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" />
<ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" />
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj" />
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj" />
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj" />
<ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" />

View file

@ -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;

View file

@ -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 },
@ -61,6 +59,14 @@ Terminal::Terminal() :
_stateMachine = std::make_unique<StateMachine>(std::move(engine));
// Until we have a true pass-through mode (GH#1173), the decision as to
// whether C1 controls are interpreted or not is made at the conhost level.
// If they are being filtered out, then we will simply never receive them.
// But if they are being accepted by conhost, there's a chance they may get
// passed through in some situations, so it's important that our state
// machine is always prepared to accept them.
_stateMachine->SetParserMode(StateMachine::Mode::AcceptC1, true);
auto passAlongInput = [&](std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite) {
if (!_pfnWriteInput)
{
@ -73,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)
@ -172,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();
@ -213,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;

View file

@ -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;

View file

@ -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
{

View file

@ -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()

View file

@ -37,6 +37,9 @@
<ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj">
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference>

View file

@ -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);

View file

@ -3,6 +3,7 @@
#include "pch.h"
#include "Profiles.h"
#include "PreviewConnection.h"
#include "Profiles.g.cpp"
#include "EnumEntry.h"
@ -10,6 +11,54 @@
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
// This function is a copy of DxFontInfo::_NearbyCollection() with
// * the call to DxFontInfo::s_GetNearbyFonts() inlined
// * checkForUpdates for GetSystemFontCollection() set to true
static wil::com_ptr<IDWriteFontCollection1> NearbyCollection(IDWriteFactory* dwriteFactory)
{
// The convenience interfaces for loading fonts from files
// are only available on Windows 10+.
wil::com_ptr<IDWriteFactory6> factory6;
// wil's query() facilities don't work inside WinRT land at the moment.
// They produce a compilation error due to IUnknown and winrt::Windows::Foundation::IUnknown being ambiguous.
if (!SUCCEEDED(dwriteFactory->QueryInterface(__uuidof(IDWriteFactory6), factory6.put_void())))
{
return nullptr;
}
wil::com_ptr<IDWriteFontCollection1> systemFontCollection;
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, systemFontCollection.addressof(), true));
wil::com_ptr<IDWriteFontSet> systemFontSet;
THROW_IF_FAILED(systemFontCollection->GetFontSet(systemFontSet.addressof()));
wil::com_ptr<IDWriteFontSetBuilder2> fontSetBuilder2;
THROW_IF_FAILED(factory6->CreateFontSetBuilder(fontSetBuilder2.addressof()));
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.get()));
{
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"))
{
fontSetBuilder2->AddFontFile(p.path().c_str());
}
}
}
wil::com_ptr<IDWriteFontSet> fontSet;
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(fontSet.addressof()));
wil::com_ptr<IDWriteFontCollection1> fontCollection;
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.get(), &fontCollection));
return fontCollection;
}
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
@ -107,8 +156,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
reinterpret_cast<::IUnknown**>(factory.put())));
// get the font collection; subscribe to updates
com_ptr<IDWriteFontCollection> fontCollection;
THROW_IF_FAILED(factory->GetSystemFontCollection(fontCollection.put(), TRUE));
const auto fontCollection = NearbyCollection(factory.get());
for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
{
@ -246,13 +294,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _profile.HasUnfocusedAppearance();
}
bool ProfileViewModel::EditableUnfocusedAppearance()
bool ProfileViewModel::EditableUnfocusedAppearance() const noexcept
{
if constexpr (Feature_EditableUnfocusedAppearance::IsEnabled())
{
return true;
}
return false;
return Feature_EditableUnfocusedAppearance::IsEnabled();
}
bool ProfileViewModel::ShowUnfocusedAppearance()
@ -286,6 +330,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _unfocusedAppearanceViewModel;
}
bool ProfileViewModel::AtlasEngineAvailable() const noexcept
{
return Feature_AtlasEngine::IsEnabled();
}
bool ProfileViewModel::UseParentProcessDirectory()
{
return StartingDirectory().empty();

View file

@ -61,12 +61,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Editor::AppearanceViewModel DefaultAppearance();
Editor::AppearanceViewModel UnfocusedAppearance();
bool HasUnfocusedAppearance();
bool EditableUnfocusedAppearance();
bool EditableUnfocusedAppearance() const noexcept;
bool ShowUnfocusedAppearance();
void CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
const IHostedInWindow& windowRoot);
void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
WINRT_PROPERTY(bool, IsBaseLayer, false);
@ -95,6 +95,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
private:
Model::Profile _profile;

View file

@ -32,6 +32,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean EditableUnfocusedAppearance { get; };
Boolean ShowUnfocusedAppearance { get; };
AppearanceViewModel UnfocusedAppearance { get; };
Boolean AtlasEngineAvailable { get; };
void CreateUnfocusedAppearance(Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes, IHostedInWindow WindowRoot);
void DeleteUnfocusedAppearance();
@ -61,6 +62,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
}
runtimeclass DeleteProfileEventArgs

View file

@ -319,7 +319,7 @@
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance, Mode=OneWay}">
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance}">
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
@ -477,6 +477,15 @@
IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
ClearSettingValue="{x:Bind State.Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind State.Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.UseAtlasEngineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.AtlasEngineAvailable}">
<ToggleSwitch IsOn="{x:Bind State.Profile.UseAtlasEngine, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</PivotItem>

View file

@ -927,6 +927,10 @@
<value>Controls what happens when the application emits a BEL character.</value>
<comment>A description for what the "bell style" setting does. Presented near "Profile_BellStyle".{Locked="BEL"}</comment>
</data>
<data name="Profile_UseAtlasEngine.Header" xml:space="preserve">
<value>Enable experimental text rendering engine</value>
<comment>An option to enable an experimental text rendering engine</comment>
</data>
<data name="Profile_BellStyleAudible.Content" xml:space="preserve">
<value>Audible</value>
<comment>An option to choose from for the "bell style" setting. When selected, an audible cue is used to notify the user.</comment>

View file

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
// pch.h
@ -51,8 +51,7 @@
#include <shlobj.h>
#include <shobjidl_core.h>
#include <dwrite.h>
#include <dwrite_1.h>
#include <dwrite_3.h>
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"

View file

@ -9,8 +9,11 @@
#include "ActionAndArgs.h"
#include "JsonUtils.h"
#include "FileUtils.h"
#include "../../types/inc/utils.hpp"
static constexpr std::wstring_view stateFileName{ L"state.json" };
static constexpr std::wstring_view elevatedStateFileName{ L"elevated-state.json" };
static constexpr std::string_view TabLayoutKey{ "tabLayout" };
static constexpr std::string_view InitialPositionKey{ "initialPosition" };
static constexpr std::string_view InitialSizeKey{ "initialSize" };
@ -85,15 +88,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return trait.FromJson(root);
}
// Returns the application-global ApplicationState object.
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance()
{
static auto state = winrt::make_self<ApplicationState>(GetBaseSettingsPath() / stateFileName);
return *state;
}
ApplicationState::ApplicationState(std::filesystem::path path) noexcept :
_path{ std::move(path) },
ApplicationState::ApplicationState(const std::filesystem::path& stateRoot) noexcept :
_sharedPath{ stateRoot / stateFileName },
_elevatedPath{ stateRoot / elevatedStateFileName },
_throttler{ std::chrono::seconds(1), [this]() { _write(); } }
{
_read();
@ -102,9 +99,21 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// The destructor ensures that the last write is flushed to disk before returning.
ApplicationState::~ApplicationState()
{
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_Start",
TraceLoggingDescription("Event at the start of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
// This will ensure that we not just cancel the last outstanding timer,
// but instead force it to run as soon as possible and wait for it to complete.
_throttler.flush();
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_End",
TraceLoggingDescription("Event at the end of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
// Re-read the state.json from disk.
@ -113,34 +122,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_read();
}
// Returns the state.json path on the disk.
winrt::hstring ApplicationState::FilePath() const noexcept
bool ApplicationState::IsStatePath(const winrt::hstring& filename)
{
return winrt::hstring{ _path.wstring() };
static const auto sharedPath{ _sharedPath.filename() };
static const auto elevatedPath{ _elevatedPath.filename() };
return filename == sharedPath || filename == elevatedPath;
}
// Generate all getter/setters
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
type ApplicationState::name() const noexcept \
{ \
const auto state = _state.lock_shared(); \
const auto& value = state->name; \
return value ? *value : type{ __VA_ARGS__ }; \
} \
\
void ApplicationState::name(const type& value) noexcept \
{ \
{ \
auto state = _state.lock(); \
state->name.emplace(value); \
state->name##Changed = true; \
} \
\
_throttler(); \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// Method Description:
// - See GH#11119. Removes all of the data in this ApplicationState object
// and resets it to the defaults. This will delete the state file! That's
@ -156,57 +144,58 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void ApplicationState::Reset() noexcept
try
{
LOG_LAST_ERROR_IF(!DeleteFile(_path.c_str()));
LOG_LAST_ERROR_IF(!DeleteFile(_sharedPath.c_str()));
LOG_LAST_ERROR_IF(!DeleteFile(_elevatedPath.c_str()));
*_state.lock() = {};
}
CATCH_LOG()
Json::Value ApplicationState::_getRoot(const locked_hfile& file) const noexcept
{
Json::Value root;
try
{
const auto data = ReadUTF8FileLocked(file);
if (data.empty())
{
return root;
}
std::string errs;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
if (!reader->parse(data.data(), data.data() + data.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
}
CATCH_LOG()
return root;
}
// Deserializes the state.json at _path into this ApplicationState.
// Deserializes the state.json and user-state (or elevated-state if
// elevated) into this ApplicationState.
// * ANY errors during app state will result in the creation of a new empty state.
// * ANY errors during runtime will result in changes being partially ignored.
void ApplicationState::_read() const noexcept
try
{
auto state = _state.lock();
const auto file = OpenFileReadSharedLocked(_path);
std::string errs;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
auto root = _getRoot(file);
// GetValueForKey() comes in two variants:
// * take a std::optional<T> reference
// * return std::optional<T> by value
// At the time of writing the former version skips missing fields in the json,
// but we want to explicitly clear state fields that were removed from state.json.
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
if (!state->name##Changed) \
{ \
state->name = JsonUtils::GetValueForKey<std::optional<type>>(root, key); \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// First get shared state out of `state.json`.
const auto sharedData = _readSharedContents().value_or(std::string{});
if (!sharedData.empty())
{
Json::Value root;
if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
// - If we're elevated, we want to only load the Shared properties
// from state.json. We'll then load the Local props from
// `elevated-state.json`
// - If we're unelevated, then load _everything_ from state.json.
if (::Microsoft::Console::Utils::IsElevated())
{
// Only load shared properties if we're elevated
FromJson(root, FileSource::Shared);
// Then, try and get anything in elevated-state
if (const auto localData{ _readLocalContents().value_or(std::string{}) }; !localData.empty())
{
Json::Value root;
if (!reader->parse(localData.data(), localData.data() + localData.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
FromJson(root, FileSource::Local);
}
}
else
{
// If we're unelevated, then load everything.
FromJson(root, FileSource::Shared | FileSource::Local);
}
}
}
CATCH_LOG()
@ -214,29 +203,191 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// * Errors are only logged.
// * _state->_writeScheduled is set to false, signaling our
// setters that _synchronize() needs to be called again.
void ApplicationState::_write() noexcept
void ApplicationState::_write() const noexcept
try
{
// re-read the state so that we can only update the properties that were changed.
Json::Value root{};
Json::StreamWriterBuilder wbuilder;
// When we're elevated, we've got to be tricky. We don't want to write
// our window state, allowed commandlines, and other Local properties
// into the shared `state.json`. But, if we only serialize the Shared
// properties to a json blob, then we'll omit windowState entirely,
// _removing_ the window state of the unelevated instance. Oh no!
//
// So, to be tricky, we'll first _load_ the shared state to a json blob.
// We'll then serialize our view of the shared properties on top of that
// blob. Then we'll write that blob back to the file. This will
// round-trip the Local properties for the unelevated instances
// untouched in state.json
//
// After that's done, we'll write our Local properties into
// elevated-state.json.
if (::Microsoft::Console::Utils::IsElevated())
{
auto state = _state.lock();
const auto file = OpenFileRWExclusiveLocked(_path);
root = _getRoot(file);
std::string errs;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
Json::Value root;
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
if (state->name##Changed) \
{ \
JsonUtils::SetValueForKey(root, key, state->name); \
state->name##Changed = false; \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// First load the contents of state.json into a json blob. This will
// contain the Shared properties and the unelevated instance's Local
// properties.
const auto sharedData = _readSharedContents().value_or(std::string{});
if (!sharedData.empty())
{
if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
}
// Layer our shared properties on top of the blob from state.json,
// and write it back out.
_writeSharedContents(Json::writeString(wbuilder, _toJsonWithBlob(root, FileSource::Shared)));
Json::StreamWriterBuilder wbuilder;
const auto content = Json::writeString(wbuilder, root);
WriteUTF8FileLocked(file, content);
// Finally, write our Local properties back to elevated-state.json
_writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local)));
}
else
{
// We're unelevated, this is easy. Just write everything back out.
_writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local | FileSource::Shared)));
}
}
CATCH_LOG()
// Returns the application-global ApplicationState object.
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance()
{
std::filesystem::path root{ GetBaseSettingsPath() };
static auto state = winrt::make_self<ApplicationState>(root);
return *state;
}
// Method Description:
// - Loads data from the given json blob. Will only read the data that's in
// the specified parseSource - so if we're reading the Local state file,
// we won't destroy previously parsed Shared data.
// - READ: there's no layering for app state.
void ApplicationState::FromJson(const Json::Value& root, FileSource parseSource) const noexcept
{
auto state = _state.lock();
// GetValueForKey() comes in two variants:
// * take a std::optional<T> reference
// * return std::optional<T> by value
// At the time of writing the former version skips missing fields in the json,
// but we want to explicitly clear state fields that were removed from state.json.
//
// GH#11222: We only load properties that are of the same type (Local or
// Shared) which we requested. If we didn't want to load this type of
// property, just skip it.
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
if (WI_IsFlagSet(parseSource, source)) \
state->name = JsonUtils::GetValueForKey<std::optional<type>>(root, key);
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
}
Json::Value ApplicationState::ToJson(FileSource parseSource) const noexcept
{
Json::Value root{ Json::objectValue };
return _toJsonWithBlob(root, parseSource);
}
Json::Value ApplicationState::_toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept
{
{
auto state = _state.lock_shared();
// GH#11222: We only write properties that are of the same type (Local
// or Shared) which we requested. If we didn't want to serialize this
// type of property, just skip it.
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
if (WI_IsFlagSet(parseSource, source)) \
JsonUtils::SetValueForKey(root, key, state->name);
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
}
return root;
}
// Generate all getter/setters
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
type ApplicationState::name() const noexcept \
{ \
const auto state = _state.lock_shared(); \
const auto& value = state->name; \
return value ? *value : type{ __VA_ARGS__ }; \
} \
\
void ApplicationState::name(const type& value) noexcept \
{ \
{ \
auto state = _state.lock(); \
state->name.emplace(value); \
} \
\
_throttler(); \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// Method Description:
// - Read the contents of our "shared" state - state that should be shared
// for elevated and unelevated instances. This is things like the list of
// generated profiles, the command palette commandlines.
std::optional<std::string> ApplicationState::_readSharedContents() const
{
return ReadUTF8FileIfExists(_sharedPath);
}
// Method Description:
// - Read the contents of our "local" state - state that should be kept in
// separate files for elevated and unelevated instances. This is things
// like the persisted window state, and the approved commandlines (though,
// those don't matter when unelevated).
// - When elevated, this will DELETE `elevated-state.json` if it has bad
// permissions, so we don't potentially read malicious data.
std::optional<std::string> ApplicationState::_readLocalContents() const
{
return ::Microsoft::Console::Utils::IsElevated() ?
ReadUTF8FileIfExists(_elevatedPath, true) :
ReadUTF8FileIfExists(_sharedPath, false);
}
// Method Description:
// - Write the contents of our "shared" state - state that should be shared
// for elevated and unelevated instances. This will atomically write to
// `state.json`
void ApplicationState::_writeSharedContents(const std::string_view content) const
{
WriteUTF8FileAtomic(_sharedPath, content);
}
// Method Description:
// - Write the contents of our "local" state - state that should be kept in
// separate files for elevated and unelevated instances. When elevated,
// this will write to `elevated-state.json`, and when unelevated, this
// will atomically write to `user-state.json`
void ApplicationState::_writeLocalContents(const std::string_view content) const
{
if (::Microsoft::Console::Utils::IsElevated())
{
// DON'T use WriteUTF8FileAtomic, which will write to a temporary file
// then rename that file to the final filename. That actually lets us
// overwrite the elevate file's contents even when unelevated, because
// we're effectively deleting the original file, then renaming a
// different file in it's place.
//
// We're not worried about someone else doing that though, if they do
// that with the wrong permissions, then we'll just ignore the file and
// start over.
WriteUTF8File(_elevatedPath, content, true);
}
else
{
WriteUTF8FileAtomic(_sharedPath, content);
}
}
}

View file

@ -16,21 +16,30 @@ Abstract:
#include "WindowLayout.g.h"
#include <inc/cppwinrt_utils.h>
#include <til/mutex.h>
#include <til/throttled_func.h>
#include "FileUtils.h"
#include <JsonUtils.h>
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
// If a property is Shared, then it'll be stored in `state.json`, and used
// in both elevated and unelevated instances of the Terminal. If a property
// is marked Local, then it will have separate values for elevated and
// unelevated instances.
enum FileSource : int
{
Shared = 0x1,
Local = 0x2
};
DEFINE_ENUM_FLAG_OPERATORS(FileSource);
// This macro generates all getters and setters for ApplicationState.
// It provides X with the following arguments:
// (type, function name, JSON key, ...variadic construction arguments)
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
#define MTSM_APPLICATION_STATE_FIELDS(X) \
X(std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
X(Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \
X(Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \
X(Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages")
// (source, type, function name, JSON key, ...variadic construction arguments)
#define MTSM_APPLICATION_STATE_FIELDS(X) \
X(FileSource::Shared, std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
X(FileSource::Local, Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \
X(FileSource::Shared, Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \
X(FileSource::Shared, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages") \
X(FileSource::Local, Windows::Foundation::Collections::IVector<hstring>, AllowedCommandlines, "allowedCommandlines")
struct WindowLayout : WindowLayoutT<WindowLayout>
{
@ -44,23 +53,26 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
friend ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<Model::WindowLayout>;
};
struct ApplicationState : ApplicationStateT<ApplicationState>
struct ApplicationState : public ApplicationStateT<ApplicationState>
{
static Microsoft::Terminal::Settings::Model::ApplicationState SharedInstance();
ApplicationState(std::filesystem::path path) noexcept;
ApplicationState(const std::filesystem::path& stateRoot) noexcept;
~ApplicationState();
// Methods
void Reload() const noexcept;
void Reset() noexcept;
void FromJson(const Json::Value& root, FileSource parseSource) const noexcept;
Json::Value ToJson(FileSource parseSource) const noexcept;
// General getters/setters
winrt::hstring FilePath() const noexcept;
bool IsStatePath(const winrt::hstring& filename);
// State getters/setters
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
type name() const noexcept; \
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
type name() const noexcept; \
void name(const type& value) noexcept;
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
@ -68,21 +80,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
private:
struct state_t
{
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
std::optional<type> name{ __VA_ARGS__ }; \
bool name##Changed = false;
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) std::optional<type> name{ __VA_ARGS__ };
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
};
til::shared_mutex<state_t> _state;
std::filesystem::path _sharedPath;
std::filesystem::path _elevatedPath;
til::throttled_func_trailing<> _throttler;
Json::Value _getRoot(const winrt::Microsoft::Terminal::Settings::Model::locked_hfile& file) const noexcept;
void _write() noexcept;
void _write() const noexcept;
void _read() const noexcept;
std::filesystem::path _path;
til::shared_mutex<state_t> _state;
til::throttled_func_trailing<> _throttler;
Json::Value _toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept;
std::optional<std::string> _readSharedContents() const;
void _writeSharedContents(const std::string_view content) const;
std::optional<std::string> _readLocalContents() const;
void _writeLocalContents(const std::string_view content) const;
};
}

View file

@ -30,12 +30,15 @@ namespace Microsoft.Terminal.Settings.Model
void Reload();
void Reset();
String FilePath { get; };
Boolean IsStatePath(String filename);
Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts { get; set; };
Windows.Foundation.Collections.IVector<String> RecentCommands { get; set; };
Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages { get; set; };
Windows.Foundation.Collections.IVector<String> AllowedCommandlines { get; set; };
}
}

View file

@ -8,6 +8,10 @@
#include <shlobj.h>
#include <WtExeUtils.h>
#include <aclapi.h>
#include <sddl.h>
#include <wil/token_helpers.h>
static constexpr std::string_view Utf8Bom{ u8"\uFEFF" };
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
@ -39,86 +43,44 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return baseSettingsPath;
}
locked_hfile OpenFileReadSharedLocked(const std::filesystem::path& path)
// Function Description:
// - Checks the permissions on this file, to make sure it can only be opened
// for writing by admins. We will be checking to see if the file is owned
// by the Builtin\Administrators group. If it's not, then it was likely
// tampered with.
// Arguments:
// - handle: a HANDLE to the file to check
// Return Value:
// - true if it had the expected permissions. False otherwise.
static bool _isOwnedByAdministrators(const HANDLE& handle)
{
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file);
// just lock the entire file
OVERLAPPED sOverlapped;
sOverlapped.Offset = 0;
sOverlapped.OffsetHigh = 0;
// Shared lock
THROW_LAST_ERROR_IF(!LockFileEx(file.get(),
0, // lock shared, wait to return until lock is obtained
0, // reserved, does nothing
INT_MAX, // lock INT_MAX bytes
0, // higher-order bytes, if our state file is greater than 2GB I guess this will be a problem
&sOverlapped));
return { std::move(file), sOverlapped };
// If the file is owned by the administrators group, trust the
// administrators instead of checking the DACL permissions. It's simpler
// and more flexible.
wil::unique_hlocal_security_descriptor sd;
PSID psidOwner{ nullptr };
// The psidOwner pointer references the security descriptor, so it
// doesn't have to be freed separate from sd.
const auto status = GetSecurityInfo(handle,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
&psidOwner,
nullptr,
nullptr,
nullptr,
wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(sd));
THROW_IF_WIN32_ERROR(status);
wil::unique_any_psid psidAdmins{ nullptr };
THROW_IF_WIN32_BOOL_FALSE(
ConvertStringSidToSidW(L"BA", wil::out_param_ptr<PSID*>(psidAdmins)));
return EqualSid(psidOwner, psidAdmins.get());
}
locked_hfile OpenFileRWExclusiveLocked(const std::filesystem::path& path)
{
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file);
// just lock the entire file
OVERLAPPED sOverlapped;
sOverlapped.Offset = 0;
sOverlapped.OffsetHigh = 0;
// Shared lock
THROW_LAST_ERROR_IF(!LockFileEx(file.get(),
LOCKFILE_EXCLUSIVE_LOCK, // lock exclusive, wait to return until lock is obtained
0, // reserved, does nothing
INT_MAX, // lock INT_MAX bytes
0, // higher-order bytes, if our state file is greater than 2GB I guess this will be a problem
&sOverlapped));
return { std::move(file), sOverlapped };
}
std::string ReadUTF8FileLocked(const locked_hfile& file)
{
const auto fileSize = GetFileSize(file.get(), nullptr);
THROW_LAST_ERROR_IF(fileSize == INVALID_FILE_SIZE);
// By making our buffer just slightly larger we can detect if
// the file size changed and we've failed to read the full file.
std::string buffer(static_cast<size_t>(fileSize) + 1, '\0');
DWORD bytesRead = 0;
THROW_IF_WIN32_BOOL_FALSE(ReadFile(file.get(), buffer.data(), gsl::narrow<DWORD>(buffer.size()), &bytesRead, nullptr));
// As mentioned before our buffer was allocated oversized.
buffer.resize(bytesRead);
if (til::starts_with(buffer, Utf8Bom))
{
// Yeah this memmove()s the entire content.
// But I don't really want to deal with UTF8 BOMs any more than necessary,
// as basically not a single editor writes a BOM for UTF8.
buffer.erase(0, Utf8Bom.size());
}
return buffer;
}
void WriteUTF8FileLocked(const locked_hfile& file, const std::string_view& content)
{
// truncate the file because we want to overwrite it
SetFilePointer(file.get(), 0, nullptr, FILE_BEGIN);
THROW_IF_WIN32_BOOL_FALSE(SetEndOfFile(file.get()));
const auto fileSize = gsl::narrow<DWORD>(content.size());
DWORD bytesWritten = 0;
THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), content.data(), fileSize, &bytesWritten, nullptr));
if (bytesWritten != fileSize)
{
THROW_WIN32_MSG(ERROR_WRITE_FAULT, "failed to write whole file");
}
}
// Tries to read a file somewhat atomically without locking it.
// Strips the UTF8 BOM if it exists.
std::string ReadUTF8File(const std::filesystem::path& path)
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly)
{
// From some casual observations we can determine that:
// * ReadFile() always returns the requested amount of data (unless the file is smaller)
@ -126,9 +88,40 @@ namespace winrt::Microsoft::Terminal::Settings::Model
// -> Lets add a retry-loop just in case, to not fail if the file size changed while reading.
for (int i = 0; i < 3; ++i)
{
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr) };
wil::unique_hfile file{ CreateFileW(path.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr) };
THROW_LAST_ERROR_IF(!file);
// Open the file _first_, then check if it has the right
// permissions. This prevents a "Time-of-check to time-of-use"
// vulnerability where a malicious exe could delete the file and
// replace it between us checking the permissions, and reading the
// contents. We've got a handle to the file now, which means we're
// going to read the contents of that instance of the file
// regardless. If someone replaces the file on us before we get to
// the GetSecurityInfo call below, then only the subsequent call to
// ReadUTF8File will notice it.
if (elevatedOnly)
{
const bool hadExpectedPermissions{ _isOwnedByAdministrators(file.get()) };
if (!hadExpectedPermissions)
{
// Close the handle
file.reset();
// delete the file. It's been compromised.
LOG_LAST_ERROR_IF(!DeleteFile(path.c_str()));
// Exit early, because obviously there's nothing to read from the deleted file.
return "";
}
}
const auto fileSize = GetFileSize(file.get(), nullptr);
THROW_LAST_ERROR_IF(fileSize == INVALID_FILE_SIZE);
@ -166,11 +159,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model
}
// Same as ReadUTF8File, but returns an empty optional, if the file couldn't be opened.
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path)
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly)
{
try
{
return { ReadUTF8File(path) };
return { ReadUTF8File(path, elevatedOnly) };
}
catch (const wil::ResultException& exception)
{
@ -183,9 +176,70 @@ namespace winrt::Microsoft::Terminal::Settings::Model
}
}
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content)
void WriteUTF8File(const std::filesystem::path& path,
const std::string_view& content,
const bool elevatedOnly)
{
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
SECURITY_ATTRIBUTES sa;
// stash the security descriptor here, so it will stay in context until
// after the call to CreateFile. If it gets cleaned up before that, then
// CreateFile will fail
wil::unique_hlocal_security_descriptor sd;
if (elevatedOnly)
{
// Initialize the security descriptor so only admins can write the
// file. We'll initialize the SECURITY_DESCRIPTOR with a
// single entry (ACE) -- a mandatory label (i.e. a
// LABEL_SECURITY_INFORMATION) that sets the file integrity level to
// "high", with a no-write-up policy.
//
// When accessed from a security context at a lower integrity level,
// the no-write-up policy filters out rights that aren't in the
// object type's generic read and execute set (for the file type,
// that's FILE_GENERIC_READ | FILE_GENERIC_EXECUTE).
//
// Another option we considered here was manually setting the ACLs
// on this file such that Builtin\Admins could read&write the file,
// and all users could only read.
//
// Big thanks to @eryksun in GH#11222 for helping with this. This
// alternative method was chosen because it's considerably simpler.
// The required security descriptor can be created easily from the
// SDDL string: "S:(ML;;NW;;;HI)"
// (i.e. SACL:mandatory label;;no write up;;;high integrity level)
unsigned long cb;
THROW_IF_WIN32_BOOL_FALSE(
ConvertStringSecurityDescriptorToSecurityDescriptor(L"S:(ML;;NW;;;HI)",
SDDL_REVISION_1,
wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(sd),
&cb));
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = sd.get();
sa.bInheritHandle = false;
// If we're running in an elevated context, when this file is
// created, it will automatically be owned by
// Builtin\Administrators, which will pass the above
// _isOwnedByAdministrators check.
//
// Programs running in an elevated context will be free to write the
// file, and unelevated processes will be able to read the file. An
// unelevated process could always delete the file and rename a new
// file in it's place (a la the way `vim.exe` saves files), but if
// they do that, the new file _won't_ be owned by Administrators,
// failing the above check.
}
wil::unique_hfile file{ CreateFileW(path.c_str(),
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE,
elevatedOnly ? &sa : nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr) };
THROW_LAST_ERROR_IF(!file);
const auto fileSize = gsl::narrow<DWORD>(content.size());
@ -198,7 +252,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model
}
}
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content)
void WriteUTF8FileAtomic(const std::filesystem::path& path,
const std::string_view& content)
{
// GH#10787: rename() will replace symbolic links themselves and not the path they point at.
// It's thus important that we first resolve them before generating temporary path.

View file

@ -1,41 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace winrt::Microsoft::Terminal::Settings::Model
{
// I couldn't find a wil helper for this so I made it myself
class locked_hfile
{
public:
wil::unique_hfile file;
OVERLAPPED lockedRegion;
~locked_hfile()
{
if (file)
{
// Need to unlock the file before it is closed
UnlockFileEx(file.get(), 0, INT_MAX, 0, &lockedRegion);
}
}
HANDLE get() const noexcept
{
return file.get();
}
};
std::filesystem::path GetBaseSettingsPath();
locked_hfile OpenFileReadSharedLocked(const std::filesystem::path& path);
locked_hfile OpenFileRWExclusiveLocked(const std::filesystem::path& path);
std::string ReadUTF8FileLocked(const locked_hfile& file);
void WriteUTF8FileLocked(const locked_hfile& file, const std::string_view& content);
std::string ReadUTF8File(const std::filesystem::path& path);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content);
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly = false);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content, const bool elevatedOnly = false);
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content);
}

View file

@ -382,7 +382,6 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
};
template<typename T>
struct ConversionTrait<std::unordered_map<std::string, T>>
{
std::unordered_map<std::string, T> FromJson(const Json::Value& json) const

View file

@ -73,7 +73,8 @@ Author(s):
X(hstring, Icon, "icon", L"\uE756") \
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Graceful) \
X(hstring, TabTitle, "tabTitle") \
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible)
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
X(bool, UseAtlasEngine, "experimental.useAtlasEngine", false)
#define MTSM_FONT_SETTINGS(X) \
X(hstring, FontFace, "face", DEFAULT_FONT_FACE) \

View file

@ -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>

View file

@ -79,5 +79,6 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_PROFILE_SETTING(Boolean, SnapOnInput);
INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing);
INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle);
INHERITABLE_PROFILE_SETTING(Boolean, UseAtlasEngine);
}
}

View file

@ -275,6 +275,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Fill in the remaining properties from the profile
_ProfileName = profile.Name();
_ProfileSource = profile.Source();
_UseAcrylic = profile.UseAcrylic();
_FontFace = profile.FontInfo().FontFace();
@ -297,6 +298,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_SuppressApplicationTitle = profile.SuppressApplicationTitle();
}
_UseAtlasEngine = profile.UseAtlasEngine();
_ScrollState = profile.ScrollState();
_AntialiasingMode = profile.AntialiasingMode();

View file

@ -119,6 +119,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// ------------------------ End of Core Settings -----------------------
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileSource);
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING);
@ -146,6 +148,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, hstring, EnvironmentVariables);
INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible);
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAtlasEngine, false);
INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);

View file

@ -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. -->

View file

@ -53,3 +53,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include <til/mutex.h>
#include <til/throttled_func.h>

View file

@ -51,6 +51,7 @@ namespace ControlUnitTests
// ------------------------ End of Core Settings -----------------------
WINRT_PROPERTY(winrt::hstring, ProfileName);
WINRT_PROPERTY(winrt::hstring, ProfileSource);
WINRT_PROPERTY(bool, UseAcrylic, false);
WINRT_PROPERTY(double, Opacity, .5);
WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
@ -75,6 +76,7 @@ namespace ControlUnitTests
WINRT_PROPERTY(winrt::hstring, EnvironmentVariables);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible);
WINRT_PROPERTY(bool, UseAtlasEngine, false);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);

View file

@ -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();

View file

@ -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));
}
@ -271,7 +270,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlink()
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence
stateMachine.ProcessString(L"\x1b]8;;test.url\x9c");
stateMachine.ProcessString(L"\x1b]8;;test.url\x1b\\");
VERIFY_IS_TRUE(tbi.GetCurrentAttributes().IsHyperlink());
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(tbi.GetCurrentAttributes().GetHyperlinkId()), L"test.url");
@ -281,7 +280,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlink()
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(tbi.GetCurrentAttributes().GetHyperlinkId()), L"test.url");
// Process the closing osc 8 sequences
stateMachine.ProcessString(L"\x1b]8;;\x9c");
stateMachine.ProcessString(L"\x1b]8;;\x1b\\");
VERIFY_IS_FALSE(tbi.GetCurrentAttributes().IsHyperlink());
}
@ -297,7 +296,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomId()
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence
stateMachine.ProcessString(L"\x1b]8;id=myId;test.url\x9c");
stateMachine.ProcessString(L"\x1b]8;id=myId;test.url\x1b\\");
VERIFY_IS_TRUE(tbi.GetCurrentAttributes().IsHyperlink());
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(tbi.GetCurrentAttributes().GetHyperlinkId()), L"test.url");
VERIFY_ARE_EQUAL(tbi.GetHyperlinkId(L"test.url", L"myId"), tbi.GetCurrentAttributes().GetHyperlinkId());
@ -309,7 +308,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomId()
VERIFY_ARE_EQUAL(tbi.GetHyperlinkId(L"test.url", L"myId"), tbi.GetCurrentAttributes().GetHyperlinkId());
// Process the closing osc 8 sequences
stateMachine.ProcessString(L"\x1b]8;;\x9c");
stateMachine.ProcessString(L"\x1b]8;;\x1b\\");
VERIFY_IS_FALSE(tbi.GetCurrentAttributes().IsHyperlink());
}
@ -325,7 +324,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomIdDifferentUri()
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence
stateMachine.ProcessString(L"\x1b]8;id=myId;test.url\x9c");
stateMachine.ProcessString(L"\x1b]8;id=myId;test.url\x1b\\");
VERIFY_IS_TRUE(tbi.GetCurrentAttributes().IsHyperlink());
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(tbi.GetCurrentAttributes().GetHyperlinkId()), L"test.url");
VERIFY_ARE_EQUAL(tbi.GetHyperlinkId(L"test.url", L"myId"), tbi.GetCurrentAttributes().GetHyperlinkId());
@ -333,7 +332,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomIdDifferentUri()
const auto oldAttributes{ tbi.GetCurrentAttributes() };
// Send any other text
stateMachine.ProcessString(L"\x1b]8;id=myId;other.url\x9c");
stateMachine.ProcessString(L"\x1b]8;id=myId;other.url\x1b\\");
VERIFY_IS_TRUE(tbi.GetCurrentAttributes().IsHyperlink());
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(tbi.GetCurrentAttributes().GetHyperlinkId()), L"other.url");
VERIFY_ARE_EQUAL(tbi.GetHyperlinkId(L"other.url", L"myId"), tbi.GetCurrentAttributes().GetHyperlinkId());
@ -356,58 +355,58 @@ void TerminalCoreUnitTests::TerminalApiTest::SetTaskbarProgress()
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set some values for taskbar state and progress through state machine
stateMachine.ProcessString(L"\x1b]9;4;1;50\x9c");
stateMachine.ProcessString(L"\x1b]9;4;1;50\x1b\\");
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(50));
// Reset to 0
stateMachine.ProcessString(L"\x1b]9;4;0;0\x9c");
stateMachine.ProcessString(L"\x1b]9;4;0;0\x1b\\");
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set an out of bounds value for state
stateMachine.ProcessString(L"\x1b]9;4;5;50\x9c");
stateMachine.ProcessString(L"\x1b]9;4;5;50\x1b\\");
// Nothing should have changed (dispatch should have returned false)
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set an out of bounds value for progress
stateMachine.ProcessString(L"\x1b]9;4;1;999\x9c");
stateMachine.ProcessString(L"\x1b]9;4;1;999\x1b\\");
// Progress should have been clamped to 100
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(100));
// Don't specify any params
stateMachine.ProcessString(L"\x1b]9;4\x9c");
stateMachine.ProcessString(L"\x1b]9;4\x1b\\");
// State and progress should both be reset to 0
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Specify additional params
stateMachine.ProcessString(L"\x1b]9;4;1;80;123\x9c");
stateMachine.ProcessString(L"\x1b]9;4;1;80;123\x1b\\");
// Additional params should be ignored, state and progress still set normally
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
// Edge cases + trailing semicolon testing
stateMachine.ProcessString(L"\x1b]9;4;2;\x9c");
stateMachine.ProcessString(L"\x1b]9;4;2;\x1b\\");
// String should be processed correctly despite the trailing semicolon,
// taskbar progress should remain unchanged from previous value
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
stateMachine.ProcessString(L"\x1b]9;4;3;75\x9c");
stateMachine.ProcessString(L"\x1b]9;4;3;75\x1b\\");
// Given progress value should be ignored because this is the indeterminate state,
// so the progress value should remain unchanged
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(3));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
stateMachine.ProcessString(L"\x1b]9;4;0;50\x9c");
stateMachine.ProcessString(L"\x1b]9;4;0;50\x1b\\");
// Taskbar progress should be 0 (the given value should be ignored)
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
stateMachine.ProcessString(L"\x1b]9;4;2;\x9c");
stateMachine.ProcessString(L"\x1b]9;4;2;\x1b\\");
// String should be processed correctly despite the trailing semicolon,
// taskbar progress should be set to a 'minimum', non-zero value
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
@ -427,45 +426,45 @@ void TerminalCoreUnitTests::TerminalApiTest::SetWorkingDirectory()
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
// Invalid sequences should not change CWD
stateMachine.ProcessString(L"\x1b]9;9\x9c");
stateMachine.ProcessString(L"\x1b]9;9\x1b\\");
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
stateMachine.ProcessString(L"\x1b]9;9\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9\"\x1b\\");
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
stateMachine.ProcessString(L"\x1b]9;9\"C:\\\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9\"C:\\\"\x1b\\");
VERIFY_IS_TRUE(term.GetWorkingDirectory().empty());
// Valid sequences should change CWD
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\");
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\Program Files\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"C:\\Program Files\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\Program Files");
stateMachine.ProcessString(L"\x1b]9;9;\"D:\\中文\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"D:\\中文\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"D:\\中文");
// Test OSC 9;9 sequences without quotation marks
stateMachine.ProcessString(L"\x1b]9;9;C:\\\x9c");
stateMachine.ProcessString(L"\x1b]9;9;C:\\\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\");
stateMachine.ProcessString(L"\x1b]9;9;C:\\Program Files\x9c");
stateMachine.ProcessString(L"\x1b]9;9;C:\\Program Files\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"C:\\Program Files");
stateMachine.ProcessString(L"\x1b]9;9;D:\\中文\x9c");
stateMachine.ProcessString(L"\x1b]9;9;D:\\中文\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"D:\\中文");
// These OSC 9;9 sequences will result in invalid CWD. We shouldn't crash on these.
stateMachine.ProcessString(L"\x1b]9;9;\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\"\x9c");
stateMachine.ProcessString(L"\x1b]9;9;\"\"\"\"\x1b\\");
VERIFY_ARE_EQUAL(term.GetWorkingDirectory(), L"\"\"");
}

View file

@ -845,8 +845,30 @@ winrt::Windows::Foundation::IAsyncAction AppHost::_SaveWindowLayouts()
if (_logic.ShouldUsePersistedLayout())
{
const auto layoutJsons = _windowManager.GetAllWindowLayouts();
_logic.SaveWindowLayoutJsons(layoutJsons);
try
{
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Collect",
TraceLoggingDescription("Logged when collecting window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
const auto layoutJsons = _windowManager.GetAllWindowLayouts();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Save",
TraceLoggingDescription("Logged when writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_logic.SaveWindowLayoutJsons(layoutJsons);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Failed",
TraceLoggingDescription("An error occurred when collecting or writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
}
co_return;
@ -867,6 +889,12 @@ winrt::fire_and_forget AppHost::_SaveWindowLayoutsRepeat()
// per 10 seconds, if a save is requested by another source simultaneously.
if (_getWindowLayoutThrottler.has_value())
{
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_requestGetLayout",
TraceLoggingDescription("Logged when triggering a throttled write of the window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_getWindowLayoutThrottler.value()();
}
}

View file

@ -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')" />

View file

@ -18,7 +18,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -18,7 +18,7 @@
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
</Dependencies>
<Resources>

View file

@ -29,7 +29,7 @@
<Description>TAEF Packaged Cwa FullTrust Application Host Process</Description>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
</Dependencies>

View file

@ -75,7 +75,7 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.19041.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.22000.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion Condition="'$(WindowsTargetPlatformMinVersion)' == ''">10.0.18362.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>

View file

@ -79,4 +79,14 @@
<!-- This feature will not ship to Stable until it is complete. -->
<alwaysDisabledReleaseTokens />
</feature>
<feature>
<name>Feature_AtlasEngine</name>
<description>If enabled, AtlasEngine and the experimental.useAtlasEngine setting are compiled into the project</description>
<stage>AlwaysEnabled</stage>
<alwaysDisabledBrandingTokens>
<brandingToken>Release</brandingToken>
<brandingToken>WindowsInbox</brandingToken>
</alwaysDisabledBrandingTokens>
</feature>
</featureStaging>

View file

@ -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());
}

View file

@ -43,6 +43,9 @@
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference>

View file

@ -38,6 +38,9 @@
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference>
@ -71,6 +74,7 @@
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>

View file

@ -2320,9 +2320,6 @@ void ReadStringWithReadConsoleInputAHelper(HANDLE hIn, PCSTR pszExpectedText, si
while (cchRead < cchExpectedText)
{
// expected read is either the size of the buffer or the number of characters remaining, whichever is smaller.
DWORD const dwReadExpected = (DWORD)std::min(cbBuffer, cchExpectedText - cchRead);
DWORD dwRead;
if (!VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputA(hIn, irRead, (DWORD)cbBuffer, &dwRead), L"Attempt to read input into buffer."))
{

View file

@ -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 &quot;$(SolutionDir)\dep\WinAppDriver\*&quot; &quot;$(OutDir)\&quot;</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>

View file

@ -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:

View file

@ -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,

View file

@ -22,10 +22,7 @@ Revision History:
#include "ConsoleArguments.hpp"
#include "ApiRoutines.h"
#include "../renderer/inc/IRenderData.hpp"
#include "../renderer/inc/IRenderEngine.hpp"
#include "../renderer/inc/IRenderer.hpp"
#include "../renderer/inc/IFontDefaultList.hpp"
#include "../renderer/base/Renderer.hpp"
#include "../server/DeviceComm.h"
#include "../server/ConDrvDeviceComm.h"
@ -62,7 +59,7 @@ public:
std::vector<wchar_t> WordDelimiters;
Microsoft::Console::Render::IRenderer* pRender;
Microsoft::Console::Render::Renderer* pRender;
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;

View file

@ -15,6 +15,7 @@
using namespace Microsoft::Console;
using Microsoft::Console::Interactivity::ServiceLocator;
using Microsoft::Console::VirtualTerminal::StateMachine;
using Microsoft::Console::VirtualTerminal::TerminalInput;
WriteBuffer::WriteBuffer(_In_ Microsoft::Console::IIoProvider& io) :
@ -263,22 +264,35 @@ bool ConhostInternalGetSet::SetInputMode(const TerminalInput::Mode mode, const b
}
// Routine Description:
// - Sets the terminal emulation mode to either ANSI-compatible or VT52.
// PrivateSetAnsiMode is an internal-only "API" call that the vt commands can execute,
// - Sets the various StateMachine parser modes.
// SetParserMode is an internal-only "API" call that the vt commands can execute,
// but it is not represented as a function call on out public API surface.
// Arguments:
// - ansiMode - set to true to enable the ANSI mode, false for VT52 mode.
// - mode - the parser mode to change.
// - enabled - set to true to enable the mode, false to disable it.
// Return Value:
// - true if successful. false otherwise.
bool ConhostInternalGetSet::PrivateSetAnsiMode(const bool ansiMode)
bool ConhostInternalGetSet::SetParserMode(const StateMachine::Mode mode, const bool enabled)
{
auto& stateMachine = _io.GetActiveOutputBuffer().GetStateMachine();
stateMachine.SetAnsiMode(ansiMode);
auto& terminalInput = _io.GetActiveInputBuffer()->GetTerminalInput();
terminalInput.SetInputMode(TerminalInput::Mode::Ansi, ansiMode);
stateMachine.SetParserMode(mode, enabled);
return true;
}
// Routine Description:
// - Retrieves the various StateMachine parser modes.
// GetParserMode is an internal-only "API" call that the vt commands can execute,
// but it is not represented as a function call on out public API surface.
// Arguments:
// - mode - the parser mode to query.
// Return Value:
// - true if the mode is enabled. false if disabled.
bool ConhostInternalGetSet::GetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode) const
{
auto& stateMachine = _io.GetActiveOutputBuffer().GetStateMachine();
return stateMachine.GetParserMode(mode);
}
// Routine Description:
// - Connects the PrivateSetScreenMode call directly into our Driver Message servicing call inside Conhost.exe
// PrivateSetScreenMode is an internal-only "API" call that the vt commands can execute,
@ -538,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
@ -594,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

View file

@ -73,8 +73,9 @@ public:
const SMALL_RECT& window) override;
bool SetInputMode(const Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) override;
bool SetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode, const bool enabled) override;
bool GetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode) const override;
bool PrivateSetAnsiMode(const bool ansiMode) override;
bool PrivateSetScreenMode(const bool reverseMode) override;
bool PrivateSetAutoWrapMode(const bool wrapAtEOL) override;
@ -100,7 +101,6 @@ public:
bool GetUserDefaultCursorStyle(CursorType& style) override;
bool SetCursorStyle(CursorType const style) override;
bool SetCursorColor(COLORREF const color) override;
bool PrivateRefreshWindow() override;
@ -118,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,

View file

@ -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

View file

@ -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);
};

View file

@ -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());

View file

@ -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);

View file

@ -16,7 +16,6 @@ Selection::Selection() :
_fSelectionVisible(false),
_ulSavedCursorSize(0),
_fSavedCursorVisible(false),
_savedCursorColor(INVALID_COLOR),
_savedCursorType(CursorType::Legacy),
_dwSelectionFlags(0),
_fLineSelection(true),

View file

@ -174,7 +174,6 @@ private:
COORD _coordSavedCursorPosition;
ULONG _ulSavedCursorSize;
bool _fSavedCursorVisible;
COLORREF _savedCursorColor;
CursorType _savedCursorType;
#ifdef UNIT_TESTING

View file

@ -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);

View file

@ -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);

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