Compare commits

...

103 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
Dustin Howett 7db7ba1ac9 ci: fix spelling for inbox merge 2021-11-09 17:22:55 -06:00
Dustin Howett 89c2b6d580 Merge remote-tracking branch 'openconsole/inbox' 2021-11-09 17:16:59 -06:00
Dustin Howett 92643c1d34 Merged PR 6654362: [Git2Git] OS build fixes for f9b97c488
Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 063b86ac10af16cade5c0754adcbf27e7e9ae266

Related work items: MSFT-34534216, MSFT-36986009, MSFT-36986203
2021-11-09 23:16:26 +00:00
Dustin Howett e591d29000 Migrate OSS up to f9b97c488 2021-11-09 13:39:28 -06:00
Dustin Howett 88d58d313a Migrate OSS up to 3f1befb06 (Touch Keyboard Invocation) 2021-11-09 13:39:23 -06:00
Dustin Howett 87182554c8 Migrate OSS up to e5180fe88 2021-11-09 13:39:09 -06:00
Dustin Howett 5ff412fe6e Migrate OSS up to 5deb33260 (A11y Degenerate Word Movement) 2021-11-09 13:33:49 -06:00
Dustin Howett 30f7f2082b Migrate OSS up to 168d28b03 2021-11-09 13:33:29 -06:00
Dustin Howett e6b871da47 Migrate OSS up to d08afc4e8 (A11y End Of Buffer) 2021-11-09 13:32:34 -06:00
Dustin Howett f9c0f86705 Migrate OSS up to 4793541c 2021-11-09 13:32:14 -06:00
Dustin Howett 86da0e041f Migrate OSS up to c53fe1c2b (A11y End Of Buffer) 2021-11-09 13:26:44 -06:00
Dustin Howett a89b66f770 Merged PR 6598109: [Git2Git] Pull Request 6508625: Update TAEF to vPack 10.63 (latest)
A change required significant changes in TAEF published headers. This PR consumes those changes.

Related work items: #20301352
2021-11-09 19:21:35 +00:00
Ikko Ashimine f9b97c4880
doc: Fix typo in #885 - Terminal Settings Model.md (#11657)
Fixed typo: ocurred -> occurred

* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
2021-11-08 12:18:50 -08:00
Mike Griese a74c37bbcd
Don't crash if we fail to BeginBufferedPaint (#11674)
Fixes MSFT:34673647, at least I'm pretty sure. That's only ever hit a few
times externally, and internally it's hitting a lot on 1.9.1942 builds, which
doesn't really make any sense.
2021-11-05 19:26:59 +00:00
Sergey 55dbda02a5
fix build error at 74d21af (#11691)
#11404 and #11653 both added WM_SYSCOMMAND which prevents build. This fixes it.
2021-11-05 19:26:03 +00:00
Sergey 7aae2e9100
Fix missing window border when use "win+arrow down" in fullscreen mode in Terminal (#11653)
Window sends an event that requests exit from fullscreen then SC_RESTORE messages is sent and it is in fullscreen mode.
Closes #10607

## Validation Steps Performed
Border and tabbar now appear after exiting fullscreen via "win+arrow down".
2021-11-04 23:46:57 +00:00
Kai 74d21afacf
README.md: HTTP => HTTPS (#11671)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Checked the link, skipping the redirect HTTP => HTTPS this way 0:-)

This one
http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54
is still only available via HTTP, sadly.

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References
<http://www.runasradio.com/Shows/Show/645> is being redirected to <https://www.runasradio.com/Shows/Show/645>

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* N/A Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* N/A Tests added/passed
* N/A Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* N/A Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## ~~Detailed Description of the Pull Request / Additional comments~~

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Opened the link.
2021-11-04 22:45:19 +00:00
PankajBhojwani 52b4bb760f
Unify splitting panes and creating new tabs (#11305)
Implements `_MakePane` in `TerminalPage`, which creates a pane that then can be used to pass into another pane to split or to create a new tab with. Places where we split pane or create a new tab now use `_MakePane`. 

## PR Checklist
* [x] Closes #11021
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] I work here

## Validation Steps Performed
Stands up to manual testing with multiple new pane/new tab commands as well as startup actions
2021-11-04 22:29:58 +00:00
James Holderness b604117421
Standardize the color table order (#11602)
## Summary of the Pull Request

In the original implementation, we used two different orderings for the color tables. The WT color table used ANSI order, while the conhost color table used a Windows-specific order. This PR standardizes on the ANSI color order everywhere, so the usage of indexed colors is consistent across both parts of the code base, which will hopefully allow more of the code to be shared one day.

## References

This is another small step towards de-duplicating `AdaptDispatch` and `TerminalDispatch` for issue #3849, and is essentially a followup to the SGR dispatch refactoring in PR #6728.

## PR Checklist
* [x] Closes #11461
* [x] CLA signed.
* [x] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number where discussion took place: #11461

## Detailed Description of the Pull Request / Additional comments

Conhost still needs to deal with legacy attributes using Windows color order, so those values now need to be transposed to ANSI colors order when creating a `TextAttribute` object. This is done with a simple mapping table, which also handles the translation of the default color entries, so it's actually slightly faster than the original code.

And when converting `TextAttribute` values back to legacy console attributes, we were already using a mapping table to handle the narrowing of 256-color values down to 16 colors, so we just needed to adjust that table to account for the translation from ANSI to Windows, and then could make use of the same table for both 256-color and 16-color values.

There are also a few places in conhost that read from or write to the color tables, and those now need to transpose the index values. I've addressed this by creating separate `SetLegacyColorTableEntry` and `GetLegacyColorTableEntry` methods in the `Settings` class which take care of the mapping, so it's now clearer in which cases the code is dealing with legacy values, and which are ANSI values.

These methods are used in the `SetConsoleScreenBufferInfoEx` and `GetConsoleScreenBufferInfoEx` APIs, as well as a few place where color preferences are handled (the registry, shortcut links, and the properties dialog), none of which are particularly sensitive to performance. However, we also use the legacy table when looking up the default colors for rendering (which happens a lot), so I've refactored that code so the default color calculations now only occur once per frame.

The plus side of all of this is that the VT code doesn't need to do the index translation anymore, so we can finally get rid of all the calls to `XTermToWindowsIndex`, and we no longer need a separate color table initialization method for conhost, so I was able to merge a number of color initialization methods into one. We also no longer need to translate from legacy values to ANSI when generating VT sequences for conpty.

The one exception to that is the 16-color VT renderer, which uses the `TextColor::GetLegacyIndex` method to approximate 16-color equivalents for RGB and 256-color values. Since that method returns a legacy index, it still needs to be translated to ANSI before it can be used in a VT sequence. But this should be no worse than it was before.

One more special case is conhost's secret _Color Selection_ feature. That uses `Ctrl`+Number and `Alt`+Number key sequences to highlight parts of the buffer, and the mapping from number to color is based on the Windows color order. So that mapping now needs to be transposed, but that's also not performance sensitive.

The only thing that I haven't bothered to update is the trace logging code in the `Telemetry` class, which logs the first 16 entries in the color table. Those entries are now going to be in a different order, but I didn't think that would be of great concern to anyone.

## Validation Steps Performed

A lot of unit tests needed to be updated to use ANSI color constants when setting indexed colors, where before they might have been expecting values in Windows order. But this replaced a wild mix of different constants, sometimes having to use bit shifting, as well as values mapped with `XTermToWindowsIndex`, so I think the tests are a whole lot clearer now. Only a few cases have been left with literal numbers where that seemed more appropriate.

In addition to getting the unit tests working, I've also manually tested the behaviour of all the console APIs which I thought could be affected by these changes, and confirmed that they produced the same results in the new code as they did in the original implementation.

This includes:
- `WriteConsoleOutput`
- `ReadConsoleOutput`
- `SetConsoleTextAttribute` with `WriteConsoleOutputCharacter`
- `FillConsoleOutputAttribute` and `FillConsoleOutputCharacter` 
- `ScrollConsoleScreenBuffer`
- `GetConsoleScreenBufferInfo`
- `GetConsoleScreenBufferInfoEx`
- `SetConsoleScreenBufferInfoEx`

I've also manually tested changing colors via the console properties menu, the registry, and shortcut links, including setting default colors and popup colors. And I've tested that the "Quirks Mode" is still working as expected in PowerShell.

In terms of performance, I wrote a little test app that filled a 80x9999 buffer with random color combinations using `WriteConsoleOutput`, which I figured was likely to be the most performance sensitive call, and I think it now actually performs slightly better than the original implementation.

I've also tested similar code - just filling the visible window - with SGR VT sequences of various types, and the performance seems about the same as it was before.
2021-11-04 22:13:22 +00:00
PankajBhojwani 761203d95e
Remove unused rendering settings from profile (#11685)
The `ForceFullRepaintRendering` and `SoftwareRendering` are global only and for some reason were in profile. This commit removes them.

Reference: https://github.com/microsoft/terminal/pull/11416#discussion_r742030103
2021-11-04 14:50:59 -05:00
PankajBhojwani 4241d1c19e
Update _OpenSettingsUI to OpenSettingsUI (#11686)
#11404 changed `_OpenSettingsUI` to `OpenSettingsUI` in `TerminalPage`, but there is still one leftover reference to `_OpenSettingsUI`. This commit fixes that.
2021-11-04 14:49:22 -05:00
Sergey ab6ba9bdbb
Add settings entry into titlebar context menu (#11404)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Adds ability for app to change system context menu

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #9666 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2021-11-04 16:47:58 +00:00
Mike Griese 8826cc028b
Make sure to format the error message with an UNSIGNED int (#11667)
Closes #11556
![image](https://user-images.githubusercontent.com/18356694/139715591-b18ef7c1-2967-42a5-9528-2522220aa177.png)
2021-11-03 22:27:41 +00:00
Mike Griese d3ca0e7878
Add trimPaste to the schema, too (#11644)
Closes #11642

  See also https://github.com/MicrosoftDocs/terminal/pull/435
2021-11-03 10:55:16 -05:00
PankajBhojwani 726b428184
Use X-macros to simplify new setting creation in SettingsModel (#11416)
Introduces X-macros to reduce the number of places we need to write essentially the same line of code but for a different setting (declaring it in the header file, in `Copy`, `LayerJson`, `ToJson`, etc).
2021-11-03 15:01:20 +00:00
James Holderness 27e042b784
Default all G-sets to ASCII unless ISO-2022 is requested (#11658)
## Summary of the Pull Request

There is a non-zero subset of applications that randomly output _Locking Shift_ escape sequences which will invoke a character set from G2 or G3 into the left half of the code table. If those G-sets are mapped to Latin1, that can result in the terminal producing output that appears to be broken. This PR now defaults all G-sets to ASCII, to prevent an unintentional _Locking Shift_ from having any effect.

## PR Checklist
* [x] Closes #10408
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number where discussion took place: #10408

## Detailed Description of the Pull Request / Additional comments

Most other modern terminals also default to ASCII in all G-sets, so this shouldn't break any modern applications. Legacy 8-bit applications may still expect the G2 and G3 sets mapped to Latin1, but they would also need to have the ISO-2022 encoding enabled, so we can keep them happy by setting G2 and G3 correctly when the ISO-2022 encoding is requested.

## Validation Steps Performed

I've manually confirmed that `echo -e "\en"` and `echo -e "\eo"` no longer have any visible effect on the output (at least without first invoking another character set into G2 or G3). I've also confirmed that they do still work as expected (i.e. selecting Latin1) after enabling the ISO-2022 encoding.
2021-11-03 00:48:05 +00:00
Mike Griese 3667678df1
Fix the cmdpal moving the infobar down (#11670)
Just read the code, it's immediately obvious what I messed up

Closes #11645


@DHowett turns out I was wrong, I could get this one done before 5 😜
2021-11-02 13:45:57 +00:00
PankajBhojwani a7ce93a357
Check that the control exists before we try to focus it (#11635)
## Summary of the Pull Request
When we are on a settings UI tab, `_GetActiveControl` returns a `nullptr`, make sure not to try and focus it in that case

## PR Checklist
* [x] Closes #11633 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
No longer crashes
2021-10-29 14:09:41 +00:00
Mike Griese b90f3605a2
Fix the wt action in defterm windows (#11646)
This is a pretty obvious typo in retrospect. Never hit it before, because in all non-defterm windows, the `_startupActions` always has one action. 

* [x] Closes #11463
2021-10-29 14:09:38 +00:00
Leonard Hecker 95cc7d9625
Add noexcept to all FontInfo structs (#11640)
FontInfoBase and it's descendents are missing noexcept annotations, which
virally forces other code to not be noexcept as well during AuditMode checks.
Apart from adding noexcept, this commit also
* Passes std::wstring_view by reference.
* Pass the FillLegacyNameBuffer argument as a simple pointer-to-array,
  allowing us to fill the buffer with a single memcpy.
  (gsl::span's iterators inhibit any internal STL optimizations.)
* Move operator== declarations inside the class to reduce code size.

All other changes are an effect of the virality of noexcept.

This is an offshoot from #11623.

## Validation Steps Performed
* It still compiles ✔️
2021-10-29 14:08:41 +00:00
Mike Griese 1cedac6a33
Fix the opacity slider (#11643)
I can't even write a description for this. Just read the code change, you'll see what I goofed.

Regressed in #11372

Closes #11555
2021-10-29 14:06:43 +00:00
Love F 756fd444b1
Trim trailing whitespace option (#11473)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Opt in setting to trim trailing white space when pasting a text into the terminal

<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #9400
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manually testing to paste text with and without trailing white spaces, with and without the option activated
2021-10-28 15:38:23 +00:00
Leonard Hecker 5bc094e12a
Improve conhost CPU usage during text selection (#11634) 2021-10-28 14:08:53 +02:00
Leonard Hecker 8560b4adfb
Fix OpenConsoleProxy for Debug builds (#11632) 2021-10-27 19:59:28 +02:00
Leonard Hecker fe26a6efc0
Fix loading of fragments that update multiple profiles (#11598)
The "updates" key is an alternative "guid" key for fragment profiles.
But SettingsLoader::_appendProfile stores and deduplicates profiles according
to their "guid" only. We need to modify the function to optionally store
profiles by their "updates" key as well, otherwise multiple fragment
profiles without "guid" might collide as they produce the same default GUID.

## PR Checklist
* [x] Closes #11597
* [x] I work here
* [ ] Tests added/passed
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
* Unit tests pass ✔️
* Issue #11597 doesn't reproduce anymore ✔️
2021-10-27 01:43:10 +00:00
Mike Griese 6d091f37b3
More roadmap updates circa October 2021 (#11575)
We don't actually have a hard date for 2.0 anymore, so I'm removing those dates to make room for 1.13, 1.14, etc. Also updated the list of milestones with the current state. We're actually doing pretty darn good (considering there was a bit of a global pandemic to contend with!)
2021-10-26 16:31:41 -05:00
Leonard Hecker 9aa4a115aa
Improve Base64::Decode performance (#11467)
This commit renames `Base64::s_Decode` into `Base64::Decode` and improves its
average performance on short strings of less than 200 characters by 4.5x.
This is achieved by implementing a classic base64 decoder that reads 4
characters at a time and produces 3 output bytes. Furthermore a small
128 byte lookup table is used to quickly map characters to values.

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

## Validation Steps Performed
* Run WSL in Windows Terminal
* Run `printf "\033]52;c;aHR0cHM6Ly9naXRodWIuY29tL21pY3Jvc29mdC90ZXJtaW5hbC9wdWxsLzExNDY3\a"`
* Clipboard contains `https://github.com/microsoft/terminal/pull/11467` ✔️
2021-10-26 21:30:25 +00:00
James Holderness 7b7dea009c
Consolidate the interfaces for setting VT input modes (#11384)
Instead of having a separate method for setting each mouse and keyboard
mode, this PR consolidates them all into a single method which takes a
mode parameter, and stores the modes in a `til::enumset` rather than
having a separate `bool` for each mode.

This enables us to get rid of a lot of boilerplate code, and makes the
code easier to extend when we want to introduce additional modes in the
future. It'll also makes it easier to read back the state of the various
modes when implementing the `DECRQM` query.

Most of the complication is in the `TerminalInput` class, which had to
be adjusted to work with an `enumset` in place of all the `bool` fields.
For the rest, it was largely a matter of replacing calls to all the old
mode setting methods with the new `SetInputMode` method, and deleting a
bunch of unused code.

One thing worth mentioning is that the `AdaptDispatch` implementation
used to have a `_ShouldPassThroughInputModeChange` method that was
called after every mode change. This code has now been moved up into the
`SetInputMode` implementation in `ConhostInternalGetSet` so it's just
handled in one place. Keeping this out of the dispatch class will also
be beneficial for sharing the implementation with `TerminalDispatch`.

## Validation

The updated interface necessitated some adjustments to the tests in
`AdapterTest` and `MouseInputTest`, but the essential structure of the
tests remains unchanged, and everything still passes.

I've also tested the keyboard and mouse modes in Vttest and confirmed
they still work at least as well as they did before (both conhost and
Windows Terminal), and I tested the alternate scroll mode manually
(conhost only).

Simplifying the `ConGetSet` and `ITerminalApi` is also part of the plan
to de-duplicate the `AdaptDispatch` and `TerminalDispatch`
implementation (#3849).
2021-10-26 21:12:22 +00:00
Mike Griese a916a5d9de
Make sure the infobar is inserted before the tab content, not on top of (#11609)
Fixes #11606

This is weird, but the infobars would appear totally on top of the
TerminalPage when `showTabsInTitlebar:false`. This would result in the infobar
obscuring the tabs.

Now, the infobars are strictly inserted after the tabs, before the content. So
when they appear, they will reduce the amount of space usable for the control.
That is a little annoying, but preferable to the tabs totally not existing.

Relevant conversation notes from #10798:

> > If the info bar is not local to the tab, then its location between the tab
> > bar (when the title bar is hidden) and the terminal panes feels
> > misleading. Should it instead be above the tab bar or below the terminal
> > panes?
>
> You're... not wrong here. It's maybe not the best place for it, but _on top_
> of the tabs would look insane, and probably wouldn't even work easily, given
> the way we reparent the tab row into the titlebar.
>
> In the pane itself would make more sense, but that runs abreast of all sorts
> of things like #9024, #4998, which might make more sense.

I'm just gonna go with this now, because it's _better_ than before, while we
work out what's _best_.

![gh-11606-fix](https://user-images.githubusercontent.com/18356694/138729178-b96b7003-0dd2-4521-8fff-0fd2a5989f22.gif)
2021-10-26 20:12:22 +00:00
Leonard Hecker def1bdd693
Compile OpenConsoleProxy without CRT (#11610)
After this commit OpenConsoleProxy will be built without a CRT.
This cuts down its binary size and DLL dependency bloat.
We hope that this fixes a COM server activation bug if the
user doesn't have a CRT installed globally on their system.

Fixes #11529
2021-10-26 19:08:49 +00:00
Ian O'Neill 9662bc6910
Ensure the background image path is displayed in the settings UI (#11580)
## Summary of the Pull Request
Ensures that the background image path is displayed in the settings UI.

## References
One of the items on #11353

## PR Checklist
* [x] Closes #11541
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Validation Steps Performed
Set the background image path and saw that it was displayed in the settings UI.
2021-10-25 11:17:48 +00:00
Sergey f63159db59
Adds exception handling of uri creation in profile background image update (#11542)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Moves baskgroung image update releated code into separate function and adds uri path construction exeption handling.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #11361
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Tried to put garbage as a path. Terminal didn't crashed.
2021-10-25 11:17:18 +00:00
Carlos Zamora e10e1d8ef1
Remove feature flag code for editable actions page (#11576)
## Summary of the Pull Request
Removes the feature flag code for the editable actions page. Pretty straightforward.

## PR Checklist
Closes #11482
2021-10-25 11:16:49 +00:00
Blake Heimann a2f26850c6
Fixed grammatical error (#11604)
Found a small grammatical error in the documentation of this particular file.
2021-10-25 06:16:30 -05:00
Mahdi Hosseini 670ae2bd1c
Link 1.12 blog and milestones on roadmap (#11562) 2021-10-21 14:05:12 -07:00
Leonard Hecker 5cd9663269
Fixed VsDevCmd command line quoting (#11554) 2021-10-20 21:57:55 +02:00
PankajBhojwani 8b8ad75024
Update version to 1.13 on main (#11550) 2021-10-20 13:12:17 -05:00
Schuyler Rosefield 6bf1507a6c
Try to fix crash on close with saving enabled (#11440)
Don't crash if we try to save the window layout while we are closing, and try to avoid saving at all.

Might impact #11354 

## Detailed Description of the Pull Request / Additional comments
- Revoke the event handler/save throttler so we don't even try to get the window layout when we are closing
- Try to check for nullptrs, but then apply `try {} CATCH_LOG()` liberally

## Validation Steps Performed
The happy path of saving normally is still fine, but I haven't been unlucky enough to trigger the crash myself.
2021-10-19 17:12:18 -07:00
Leonard Hecker 5a23029dac
Further reduce number of generated VS profiles (#11489)
This commit reduces the number of generated VS profiles from 6 down to just 2
per VS instance. The reason we did this is out of concern of overwhelming or
annoying new users with too many profiles. Especially since it's far easier
at the moment to add new generators compared to removing them.

As before only the latest instance is not hidden by default.

## PR Checklist
* [x] I work here
* [x] Tests added/passed
* [x] As discussed in a Team Sync meeting

## Validation Steps Performed
* Installed Visual Studio 2019 and 2022 Preview
* A profile for both is generated, while the 2019 one is hidden by default ✔️
* $env:VSCMD_ARG_TGT_ARCH is x64 on my AMD64 machine ✔️
2021-10-19 23:52:00 +00:00
Mike Griese 284257a383
Add even MORE logging for defterm (#11537)
Considering the number of reports of "defterm isn't working (mysteriously)", I figured more logging current hurt. I also added a wprp profile for the defterm logging as well, which should capture conhost side things as well. 

From an elevated conhost:
```
wpr -start path\to\Terminal.wprp!Defterm.Verbose
wpr -stop %USERPROFILE%\defterm-trace.etl
```

* [x] I work here
* [x] relevant to: #10594, #11529, #11524.
2021-10-19 13:29:18 -07:00
NotWearingPants 0d5af3fedc
Remove double-space in defaults.json (#11518)
There was a double-space after a colon in `defaults.json` and `defaults-universal.json`.
2021-10-18 16:25:13 -05:00
NotWearingPants fd93c54ae3
Change action names in schema to match without regex (#11520)
## Summary of the Pull Request
Currently when configuring the action
```json
{ "command": { "action": "closeTabsAfter" } }
```
we get a schema error in VSCode: `Matches multiple schemas when only one must validate.`.

The problem is that it matches both `closeTabsAfter` and `closeTab`, since the schema uses regex patterns to match instead of plain strings. I swapped the usage of `"pattern"` with `"const"` for all actions.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments

## Validation Steps Performed
I checked and this action configuration no longer errors.
2021-10-18 16:24:35 -05:00
Leonard Hecker c1d326693c
Remove debug logging for PSReadline on newlines (#11486)
Up until this commit PSReadline caused OutputDebugString to be called
with a complex log message to on every newline. At the time of writing,
Visual Studio's Output window is fairly slow and after this change newlines
feel a fair bit snappier when running under Visual Studio's debugger.

## Validation Steps Performed
* pwsh.exe continues to work correctly ✔️
2021-10-18 10:20:34 -07:00
Leonard Hecker 2cf31ac72d
Remove last remaining winrt::hstring allocation during text output (#11487)
ControlCore::FontFaceName() is called 10/s by TSFInputControl.
The getter was modified to cache the STL string in a hstring allowing
us to return a value without temporary allocations during runtime.

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

## Validation Steps Performed
* Font face and size changes properly update TSFInputControl ✔️
2021-10-18 09:55:38 -07:00
NotWearingPants 02dd463b35
Linked missing action command objects in schema (#11519)
## Summary of the Pull Request
Currently when configuring the action
```json
{ "command": { "action": "commandPalette", "launchMode": "commandLine" }, "key": "ctrl+shift+p" }
```
or
```json
{ "command": { "action": "multipleActions", "actions": [{ "action": "paste" }] }, "key": "ctrl+shift+v" }
```
we get a schema error in VSCode. These object variants of the actions were not configured properly in the schema, so I fixed it.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments
In the schema there is a big `oneOf` for the `command` of an action under `actions`.
Commands that also accept extra arguments have an object type defined for it.
The `commandPalette` and `multipleActions` commands accept extra arguments, and also have matching `CommandPaletteAction` and `MultipleActionsAction` object types defined, but they are unused.
So I added them to the `oneOf` array in the correct placement.

## Validation Steps Performed
2021-10-18 11:42:31 -05:00
NotWearingPants 51c3011950
Fix quoted boolean defaults in schema (#11517)
## Summary of the Pull Request

The `settings.json` schema had `"default"`s for some boolean settings set as quoted strings (`"true"` / `"false"`), so I removed the quotes.

## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed
* [ ] Tests added/passed
* [ ] Documentation updated
* [x] Schema updated
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan

## Detailed Description of the Pull Request / Additional comments

VSCode autocompletes the default value when you select the setting in intellisense, so it autocompleted a string which caused a schema error. Booleans should be JSON booleans, not quoted.

## Validation Steps Performed
2021-10-18 11:42:08 -05:00
Dmitriy Fishman 1c8b71b6e7
Fix a typo in Niksa.md (#11506) 2021-10-15 17:46:49 -05:00
Dmitriy Fishman b3cc618af8
doc: Fix a UKism in CONTRIBUTING.md (#11505) 2021-10-15 17:46:26 -05:00
Carlos Zamora 02ac246807
Properly initialize XamlUiaTextRange with ProviderFromPeer (#11501)
## Summary of the Pull Request
As a part of the Interactivity split, `TermControlAutomationPeer` had to be split into `TermControlAutomationPeer` (TCAP) and `InteractivityAutomationPeer` (IAP). Just about all of the functions in `InterativityAutomationPeer` operate by calling the non-XAML UIA Provider then wrapping the resulting `UIATextRange` into a XAML format (a `XamlUiaTextRange` [XUTR]). As a part of that XUTR constructor, we need a reference to the parent provider.

We generally get that via `ProviderFromPeer()`, but IAP's `ProviderFromPeer()` returned null (presumably because IAP isn't in the UI tree, whereas TCAP is directly registered as the automation peer for the `TermControl`).

It looks like some screen readers didn't care (like NVDA, though there may be a chance we just didn't encounter an issue just yet), but Narrator definitely did.

The fix was to provide XUTR constructors the `ProviderFromPeer` from TCAP, _not_ IAP. To accomplish this, IAP now holds a weak reference to TCAP, and provides the `ProviderFromPeer` when needed. We can't cache this result because there is no guarantee that it won't change.

Some miscellaneous changes include:
- `TermControl::OnCreateAutomationPeer` now returns the existing auto peer instead of always creating a new one
- `TCAP::WrapArrayOfTextRangeProviders` was removed as it was unused (normally, this would be directly affected by the main `ProviderFromPeer` change here)
- `XUTR::GetEnclosingElement` is now hooked up to trace logging for debugging purposes

## References
Introduced in #10051
Closes #11488 

## Validation Steps Performed
 Narrator scan mode now works (verified with character, word, and line navigation)
 NVDA movement still works (verified with word and line navigation)
2021-10-13 23:01:43 +00:00
Dustin L. Howett a89c3e2f85
Add an Open Settings link to the "Default Terminal" tip (#11491)
This commit switches the [X] button in the info bar to permanently
dismiss the tip and fixes a focus transition issue.

Closes #11483
2021-10-12 22:12:21 +00:00
MPela 462d8003a7
Dismiss any open content dialog when window is moved (#11485)
## Summary of the Pull Request
When the window moves, hide any visible content dialog (only one can be shown at a time) and ensure its associated async operation is terminated.

#10922 dismisses any open popups when the window is moved or any scroll viewer scrolls. However, if you just close a Popup from the UI tree, the async operation associated to a ContentDialog (started with `dialog.ShowAsync`) does not terminate. The dialog lock that prevents opening multiple dialogs at the same time is not released, and no further dialog can be shown. 
Explicitly dismissing the only visible ContentDialog using its `Hide` method terminates the operation.

## Validation Steps Performed
Manual tests, open up dialogs and move the window (like in #11425)

References #10922 
Closes #11425
2021-10-12 18:00:06 +00:00
PankajBhojwani 275cdcf63f
Enable the editable actions page in the SUI (#11481) 2021-10-12 15:56:48 +00:00
Leon Liang 08e36123b3
Add logging for default terminal (#11458)
This PR adds some `TraceLogging` for default terminal, namely:
- [x] successfully receiving terminal handoffs
- [x] failing to receive terminal handoffs
- [x] default terminal selection changes

Closes #11452
2021-10-12 15:56:17 +00:00
Leonard Hecker b036cab850
Enable fast floating point model and fast debug linking (#11466)
This commit enables /fp:fast. This doubles the performance of the Delta E
computation in #11095 for instance. Additionally it re-enables two options for
debug builds which are normally enabled by default by Visual Studio.

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

## Validation Steps Performed
* No change in binary size
* No obvious change in behavior
2021-10-11 21:02:15 +00:00
Dustin L. Howett 4a3e50cb16
Enable the "Defaults" settings page in Stable (#11453)
This change enables access to the Defaults page in stable builds of
terminal. It is intended that we backport this feature flag edit to
1.11, so that Defaults can roll out with 1.11 when it becomes stable.
2021-10-11 16:21:32 +00:00
Leonard Hecker 0ab1529487
Improve til::gen_random documentation (#11465) 2021-10-11 17:59:40 +02:00
Mike Griese 8dd317313b
Clear out state.json when we find and empty settings.json (#11448)
If we find that the settings file doesn't exist, or is empty, then let's quick
delete the state file as well. If the user does have a state file, and not a
settings, then they probably tried to reset their settings. It might have data
in it that was only relevant for a previous iteration of the settings file. If
we don't, we'll load the old state and ignore all dynamic profiles (for
example)!

We'll remove all of the data in the `ApplicationState` object and reset it to
the defaults.

This will delete the state file!

That's the sure-fire way to make sure the data doesn't come back. If we leave
it untouched, then when we go to write the file back out, we'll first re-read
it's contents and try to overlay our new state. However, nullopts won't remove
keys from the JSON, so we'll end up with the original state in the file.

* [x] Closes #11119
* [x] Tested on a cold launch of the Terminal with an existing `state.json`
and an empty `settings.json`
* [x] Tested a hot-reload of deleting the `settings.json`
2021-10-11 15:51:47 +00:00
Leonard Hecker 479ef264b2
Implement basic profile matching (#11390)
This implements command line matching for `CascadiaSettings::GetProfileForArgs`.
The command lines for all user profiles are resolved to absolute file paths,
argument quotes are standardized ("canonicalized") and the results are cached.

When `GetProfileForArgs` is called with a Commandline() value, we "canonicalize"
the argument as well and find the profile that is the longest prefix.
If none could be found the default profile is returned.

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

## Validation Steps Performed

* Open a `cmd.exe` tab in the store-version of WT
* Run `start cmd`
  --> A tab with the `cmd.exe` profile opens
* Run `start pwsh.exe`
  --> A tab with the PowerShell 7 profile opens
* Run PowerShell 7 from the start menu
  --> A tab with the PowerShell 7 profile opens
* Create a symlink for PowerShell 7 and launch `pwsh.exe` from there
  --> A tab with the PowerShell 7 profile opens
2021-10-08 00:40:10 +00:00
PankajBhojwani dd5dbb2a40
Implement the Delta E algorithm to improve color perception (#11095)
- Implements the Delta E algorithm
- Uses the Delta E algorithm to precalculate adjusted foreground values based on possible foreground/background color pairs in the color table
- Adds a setting to use the adjusted foreground values when applicable

## PR Checklist
* [x] Closes #2638
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Before:
<img width="759" alt="color before" src="https://user-images.githubusercontent.com/26824113/131576768-b3b9eebd-5933-45de-8da8-88a985070312.png">

After (note dark blue):
<img width="760" alt="color after" src="https://user-images.githubusercontent.com/26824113/133158807-4e63198f-8a49-4d03-914e-55a5ad57d725.png">
2021-10-07 22:43:17 +00:00
Mike Griese bc4f410788
Wire up RadioButtons as groups in UIA (#11442)
I thought that microsoft/microsoft-ui-xaml#3183 might just fix this for us, but it didn't. We've got our RadioButton's all up in SettingsContainers, so they all think they're `AutomationProperties.AccessibilityView="Raw"` for some reason. If you simply add the `Content` to these, then they all end up correct in Accessibility Insights

## PR Checklist
* [x] Will take care of #11248 but I can't be the one to close it.
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated
2021-10-07 17:46:04 +00:00
Leonard Hecker 2b1468eaa2
Add a information popup about default terminals (#11397)
This commit adds a simple information popup about default terminals,
guiding first-time Windows 11 users into changing the default terminal.

## Validation Steps Performed
* Info bar pops up on Windows 11 ✔️
* Info bar can be dismissed persistently ✔️
2021-10-07 17:44:03 +00:00
Mike Griese e1c830dde0
Make sure all the commandlines are fully qualified (#11437)
This was originally in #11308. Thought we should check it in for 1.12 even
though that won't merge this release. Should slightly mitigate the number of
users that see this warning.
2021-10-07 12:18:11 -05:00
Leonard Hecker 84e7ec4f96
Fix layering issues with CascadiaSettings::_createNewProfile (#11447)
`CascadiaSettings::_createNewProfile` failed to call `_FinalizeInheritance`.
This commits fixes the issue and adds a stern warning for future me.

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

## Validation Steps Performed

* Open settings UI
* Modify font size in base layer
* _Don't_ save
* Duplicate any profile with default font size
* Ensure the duplicated profile shows the modified base layer font size ✔️
2021-10-07 16:30:34 +00:00
Mike Griese 694c6b263f
When enabling opacity on win10, automatically enable acrylic (#11372)
In #11180 we made `opacity` independent from `useAcrylic`. We also changed the mouse wheel behavior to only change opacity, and not mess with acrylic.

However, on Windows 10, vintage opacity doesn't work at all. So there, we still need to manually enable acrylic when the user requests opacity.

* [x] Closes #11285

SUI changes in action:

![auto-acrylic-win10](https://user-images.githubusercontent.com/18356694/136281935-db9a10f4-e0ad-4422-950b-0a01dc3e12c0.gif)
2021-10-07 11:39:20 +00:00
Mike Griese bd8bfa13bb
Fix opening the debug tap (#11445)
It's possible that we're about to be started, _before_
our paired connection is started. Both will get Start()'ed when
their owning TermControl is finally laid out. However, if we're
started first, then we'll immediately start printing to the other
control as well, which might not have initialized yet. If we do
that, we'll explode.

Instead, wait here until the other connection is started too,
before actually starting the connection to the client app. This
will ensure both controls are initialized before the client app
is.

Fixes #11282

Tested: Opened about 100 debug taps. They all worked. :shipit:
2021-10-06 16:11:09 -05:00
Dustin Howett dc865529b5 Migrate OSS up to f9a844dbd
# Conflicts:
#	src/inc/til/u8u16convert.h
2021-09-21 16:22:57 -05:00
Dustin Howett d26353bb32 Merged PR 6303540: Prepare command history before COOKED_READ in tests
[Git2Git] Merged PR 6303114: Prepare command history before COOKED_READ in tests

PR !6278637 introduced a dependency from COOKED_READ_DATA on the ability
to locate a command history for a process handle (here, `nullptr`).

The tests were blowing up because no such history had been allocated.

Closes MSFT-34812916
Closes MSFT-34813774
Closes MSFT-34815941
Closes MSFT-34817558
Closes MSFT-34817540 (Watson)

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev f7517e686447fc0469f6b83df19760dc3dafd577
2021-09-21 20:51:44 +00:00
Dustin Howett 431d51de4c Merged PR 6286783: Release unneeded memory more eagerly from conhost
This is equivalent to commit 8779249b1, but reflected from the OS repository.

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev a4d67e9b05039f365a1a0c58e9c63474c58073a1

Related work items: MSFT-34777060
2021-09-21 20:49:55 +00:00
Dustin Howett 184919fb24 Merged PR 6285331: [Git2Git] Merged PR 6278637: Expose attached client process context to cooked read trace
Related work items: MSFT-32957145

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev bdb25dc99dcb2f1ee483dffe883d0178ea9d18dc
2021-07-22 13:39:34 +00:00
Dustin Howett 01b5195275 Merged PR 6277720: [Git2Git] Merged PR 6275065: Trace console attach/detatch
As identified by Michael Niksa, our MDE heuristics for understanding relationship between conhost and related processes was incorrect. Exposing trace here to assist in correlation.

Related work items: MSFT-32957145

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 3c886da66d77d1aa36b52794929e388af292539c
2021-07-21 18:41:37 +00:00
Dustin Howett dfda41074d Merged PR 6274354: [Git2Git] Fix unbound read of cooked read buffer
Fix unbound read of cooked read buffer

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 756c8dcd4cf9551f5bf090b98bf3fba5498f8eff

Related work items: MSFT-32957145
2021-07-19 20:02:20 +00:00
Dustin Howett 26f4b0eacb Merged PR 6269653: Slim down conhost's dependency on shcore
An internal change CommandLineToArgVW to an apiset.

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev a71b943e06c009085d6a2bb886dd50c2d0d2c276

Related work items: MSFT-32178383
2021-07-19 19:51:47 +00:00
348 changed files with 9757 additions and 4903 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
@ -9,6 +11,7 @@ BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYPOSITION
BYCOMMAND
charconv
CLASSNOTAVAILABLE
cmdletbinding
@ -16,9 +19,11 @@ COLORPROPERTY
colspan
COMDLG
comparand
commandlinetoargv
cstdint
CXICON
CYICON
Dacl
dataobject
dcomp
DERR
@ -85,6 +90,7 @@ LSHIFT
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
memicmp
mptt
mov
@ -114,15 +120,19 @@ OSVERSIONINFOEXW
otms
OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PEXPLICIT
PICKFOLDERS
pmr
ptstr
rcx
REGCLS
RETURNCMD
rfind
roundf
RSHIFT
SACL
schandle
semver
serializer
@ -159,6 +169,8 @@ toupper
TTask
TVal
UChar
UFIELD
ULARGE
UPDATEINIFILE
userenv
wcsstr

View file

@ -1,3 +1,11 @@
atan
CPrime
HBar
HPrime
isnan
LPrime
LStep
powf
RSub
sqrtf
ULP

View file

@ -1,5 +1,6 @@
ACLs
ADMINS
advapi
altform
altforms
appendwttlogging
@ -15,6 +16,7 @@ CPLs
cpptools
cppvsdbg
CPRs
cryptbase
DACL
DACLs
diffs
@ -46,6 +48,7 @@ powershell
propkey
pscustomobject
QWORD
regedit
robocopy
SACLs
sdkddkver

View file

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

View file

@ -61,12 +61,14 @@ 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$
^src/terminal/parser/ft_fuzzer/run\.bat$
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/terminal/parser/ft_fuzzwrapper/run\.bat$
^src/terminal/parser/ut_parser/Base64Test.cpp$
^src/terminal/parser/ut_parser/run\.bat$
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
^src/tools/lnkd/lnkd\.bat$

View file

@ -508,6 +508,7 @@ dealloc
Debian
debolden
debugtype
DECAC
DECALN
DECANM
DECAUPSS
@ -668,6 +669,7 @@ dwriteglyphrundescriptionclustermap
dxgi
dxgidwm
dxinterop
dxsm
dxttbmp
eachother
eae
@ -937,6 +939,7 @@ GTP
guc
gui
guidatom
guiddef
GValue
GWL
GWLP
@ -1231,6 +1234,7 @@ KLF
KLMNO
KLMNOPQRST
KLMNOPQRSTQQQQQ
KPRIORITY
KVM
langid
LANGUAGELIST
@ -1533,6 +1537,7 @@ NOCOLOR
NOCOMM
NOCONTEXTHELP
NOCOPYBITS
nodefaultlib
nodiscard
NODUP
noexcept
@ -1641,6 +1646,7 @@ onecoreuapuuid
onecoreuuid
ONECOREWINDOWS
onehalf
oneseq
ONLCR
openbash
opencode
@ -1707,6 +1713,7 @@ pcch
PCCHAR
PCCONSOLE
PCD
pcg
pch
PCHAR
PCIDLIST
@ -1802,6 +1809,7 @@ POSX
POSXSCROLL
POSYSCROLL
ppci
PPEB
ppf
ppguid
ppidl
@ -2021,6 +2029,7 @@ Rike
RIPMSG
RIS
RMENU
rng
roadmap
robomac
roundtrip
@ -2226,6 +2235,7 @@ STARTWPARMSW
Statusline
stdafx
STDAPI
stdc
stdcall
stdcpp
stderr

View file

@ -1,5 +1,7 @@
http
www
easyrgb
php
ecma
rapidtables
WCAG

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.
@ -125,7 +139,7 @@ Team members will be happy to help review specs and guide them to completion.
### Help Wanted
Once the team have approved an issue/spec, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/terminal/labels/Help%20Wanted).
Once the team has approved an issue/spec, development can proceed. If no developers are immediately available, the spec can be parked ready for a developer to get started. Parked specs' issues will be labeled "Help Wanted". To find a list of development opportunities waiting for developer involvement, visit the Issues and filter on [the Help-Wanted label](https://github.com/microsoft/terminal/labels/Help%20Wanted).
---

View file

@ -117,7 +117,6 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## dynamic_bitset
@ -148,7 +147,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
## \{fmt\}
@ -215,7 +213,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
@ -249,7 +246,71 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
## PCG Random Number Generation
**Source**: [https://github.com/imneme/pcg-cpp](https://github.com/imneme/pcg-cpp)
### License
```
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
## ConEmu
**Source**: [https://github.com/Maximus5/ConEmu](https://github.com/Maximus5/ConEmu)
### License
```
BSD 3-Clause License
Copyright (c) 2009-2017, Maximus5 <ConEmu.Maximus5@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
# Microsoft Open Source

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

@ -214,7 +214,7 @@ resources useful and interesting:
* Windows Terminal Launch: [Build 2019
Session](https://www.youtube.com/watch?v=KMudkRcwjCw)
* Run As Radio: [Show 645 - Windows Terminal with Richard
Turner](http://www.runasradio.com/Shows/Show/645)
Turner](https://www.runasradio.com/Shows/Show/645)
* Azure Devops Podcast: [Episode 54 - Kayla Cinnamon and Rich Turner on DevOps
on the Windows
Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54)

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

@ -5,7 +5,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2021</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>12</VersionMinor>
<VersionMinor>13</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

View file

@ -4,7 +4,7 @@
Introducing exceptions to an existing non-exception-based codebase can be perilous. The console was originally written
in C at a time when C++ was relatively unused in the Windows operating system. As part of our project to modernize the
Windows console, we converted to use C++, but still had an aversion to using exception-based error handling in
our code for fear that it introduce unexpected failures. However, the STL and other libraries like it are so useful that
our code for fear that it might introduce unexpected failures. However, the STL and other libraries like it are so useful that
sometimes it's significantly simpler to use them. Given that, we have a set of rules that we follow when considering
exception use.

View file

@ -189,7 +189,7 @@ I think there might be a bit of a misunderstanding here - there are two differen
* shell applications, like `cmd.exe`, `powershell`, `zsh`, etc. These are text-only applications that emit streams of characters. They don't care at all about how they're eventually rendered to the user. These are also sometimes referred to as "commandline client" applications.
* terminal applications, like the Windows Terminal, gnome-terminal, xterm, iterm2, hyper. These are graphical applications that can be used to render the output of commandline clients.
On Windows, if you just run `cmd.exe` directly, the OS will create an instance of `conhost.exe` as the _terminal_ for `cmd.exe`. The same thing happens for `powershell.exe`, the system will creates a new conhost window for any client that's not already connected to a terminal of some sort. This has lead to an enormous amount of confusion for people thinking that a conhost window is actually a "`cmd` window". `cmd` can't have a window, it's just a commandline application. Its window is always some other terminal.
On Windows, if you just run `cmd.exe` directly, the OS will create an instance of `conhost.exe` as the _terminal_ for `cmd.exe`. The same thing happens for `powershell.exe`, the system will create a new conhost window for any client that's not already connected to a terminal of some sort. This has lead to an enormous amount of confusion for people thinking that a conhost window is actually a "`cmd` window". `cmd` can't have a window, it's just a commandline application. Its window is always some other terminal.
Any terminal can run any commandline client application. So you can use the Windows Terminal to run whatever shell you want. I use mine for both `cmd` and `powershell`, and also WSL:

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

@ -188,6 +188,10 @@
],
"type": "string"
},
"adjustIndistinguishableColors": {
"description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.",
"type": "boolean"
},
"experimental.retroTerminalEffect": {
"description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "boolean"
@ -455,7 +459,7 @@
},
"suppressApplicationTitle": {
"type": "boolean",
"default": "false",
"default": false,
"description": "When set to true, tabTitle overrides the default title of the tab and any title change messages from the application will be suppressed. When set to false, tabTitle behaves as normal"
},
"colorScheme": {
@ -502,7 +506,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "adjustFontSize"
"const": "adjustFontSize"
},
"delta": {
"type": "integer",
@ -526,7 +530,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "copy"
"const": "copy"
},
"singleLine": {
"type": "boolean",
@ -562,7 +566,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "newTab"
"const": "newTab"
}
}
}
@ -578,7 +582,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "switchToTab"
"const": "switchToTab"
},
"index": {
"type": "integer",
@ -602,7 +606,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "movePane"
"const": "movePane"
},
"index": {
"type": "integer",
@ -626,7 +630,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "moveFocus"
"const": "moveFocus"
},
"direction": {
"$ref": "#/$defs/FocusDirection",
@ -650,7 +654,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "swapPane"
"const": "swapPane"
},
"direction": {
"$ref": "#/$defs/FocusDirection",
@ -674,7 +678,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "resizePane"
"const": "resizePane"
},
"direction": {
"$ref": "#/$defs/ResizeDirection",
@ -698,7 +702,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "sendInput"
"const": "sendInput"
},
"input": {
"type": "string",
@ -725,7 +729,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "splitPane"
"const": "splitPane"
},
"split": {
"$ref": "#/$defs/SplitDirection",
@ -757,7 +761,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "openSettings"
"const": "openSettings"
},
"target": {
"type": "string",
@ -784,7 +788,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "setTabColor"
"const": "setTabColor"
},
"color": {
"$ref": "#/$defs/Color",
@ -805,7 +809,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "setColorScheme"
"const": "setColorScheme"
},
"colorScheme": {
"type": "string",
@ -829,7 +833,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "wt"
"const": "wt"
},
"commandline": {
"type": "string",
@ -853,7 +857,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "closeOtherTabs"
"const": "closeOtherTabs"
},
"index": {
"oneOf": [
@ -881,7 +885,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "closeTabsAfter"
"const": "closeTabsAfter"
},
"index": {
"oneOf": [
@ -909,7 +913,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "closeTab"
"const": "closeTab"
},
"index": {
"oneOf": [
@ -937,7 +941,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "scrollUp"
"const": "scrollUp"
},
"rowsToScroll": {
"type": [
@ -961,7 +965,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "scrollDown"
"const": "scrollDown"
},
"rowsToScroll": {
"type": [
@ -985,7 +989,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "moveTab"
"const": "moveTab"
},
"direction": {
"$ref": "#/$defs/MoveTabDirection",
@ -1008,7 +1012,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "multipleActions"
"const": "multipleActions"
},
"actions": {
"$ref": "#/$defs/ShortcutAction",
@ -1033,7 +1037,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "commandPalette"
"const": "commandPalette"
},
"launchMode": {
"$ref": "#/$defs/CommandPaletteLaunchMode",
@ -1054,7 +1058,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "findMatch"
"const": "findMatch"
},
"direction": {
"$ref": "#/$defs/FindMatchDirection",
@ -1081,7 +1085,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "newWindow"
"const": "newWindow"
}
}
}
@ -1097,7 +1101,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "prevTab"
"const": "prevTab"
},
"tabSwitcherMode": {
"$ref": "#/$defs/SwitchToAdjacentTabArgs",
@ -1118,7 +1122,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "nextTab"
"const": "nextTab"
},
"tabSwitcherMode": {
"$ref": "#/$defs/SwitchToAdjacentTabArgs",
@ -1139,7 +1143,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "renameTab"
"const": "renameTab"
},
"title": {
"type": "string",
@ -1160,7 +1164,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "renameWindow"
"const": "renameWindow"
},
"name": {
"type": "string",
@ -1181,7 +1185,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "focusPane"
"const": "focusPane"
},
"id": {
"type": "integer",
@ -1203,7 +1207,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "globalSummon"
"const": "globalSummon"
},
"desktop": {
"type": "string",
@ -1254,7 +1258,7 @@
"properties": {
"action": {
"type": "string",
"pattern": "quakeMode"
"const": "quakeMode"
}
}
}
@ -1329,6 +1333,12 @@
{
"$ref": "#/$defs/MoveTabAction"
},
{
"$ref": "#/$defs/MultipleActionsAction"
},
{
"$ref": "#/$defs/CommandPaletteAction"
},
{
"$ref": "#/$defs/FindMatchAction"
},
@ -1468,6 +1478,11 @@
"description": "When set to true, trailing white-spaces will be removed from text in rectangular (block) selection while copied to your clipboard. When set to false, the white-spaces will be preserved.",
"type": "boolean"
},
"trimPaste": {
"default": true,
"description": "When enabled, the Terminal will automatically trim trailing whitespace characters when pasting text",
"type": "boolean"
},
"experimental.detectURLs": {
"default": true,
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",
@ -1571,22 +1586,22 @@
"deprecated": true
},
"minimizeToNotificationArea": {
"default": "false",
"default": false,
"description": "When set to true, minimizing a Terminal window will no longer appear in the taskbar. Instead, a Terminal icon will appear in the notification area through which the user can access their windows.",
"type": "boolean"
},
"alwaysShowNotificationIcon": {
"default": "false",
"default": false,
"description": "When set to true, the Terminal's notification icon will always be shown in the notification area.",
"type": "boolean"
},
"showAdminShield": {
"default": "true",
"default": true,
"description": "When set to true, the Terminal's tab row will display a shield icon when the Terminal is running with administrator privileges",
"type": "boolean"
},
"useAcrylicInTabRow": {
"default": "false",
"default": false,
"description": "When set to true, the tab row will have an acrylic background with 50% opacity.",
"type": "boolean"
},
@ -1973,6 +1988,10 @@
}
]
},
"adjustIndistinguishableColors": {
"description": "When set to true, we will (when necessary) adjust the foreground color to make it more visible, based on the background color.",
"type": "boolean"
},
"scrollbarState": {
"default": "visible",
"description": "Defines the visibility of the scrollbar.",

View file

@ -268,7 +268,7 @@ Today, if the deserialization of `CascadiaSettings` encounters any errors, an ex
To get around this issue, when `CascadiaSettings` encounters a serialization error, it must internally record
any pertinent information for that error, and return the simple `CascadiaSettings` as if nothing happened.
The consumer must then call `CascadiaSettings::GetErrors()` and `CascadiaSettings::GetWarnings()` to properly
understand whether an error ocurred and how to present that to the user.
understand whether an error occurred and how to present that to the user.
#### TerminalApp: Loading and Reloading Changes

View file

@ -2,7 +2,7 @@
## Overview
This document outlines the roadmap towards delivering Windows Terminal 2.0 by Winter 2021.
This document outlines the roadmap towards delivering Windows Terminal 2.0.
## Milestones
@ -31,9 +31,9 @@ Below is the schedule for when milestones will be included in release builds of
| 2021-05-31 | [1.9] in Windows Terminal Preview<br>[1.8] in Windows Terminal | [Windows Terminal Preview 1.9 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-9-release/) |
| 2021-07-14 | [1.10] in Windows Terminal Preview<br>[1.9] in Windows Terminal | [Windows Terminal Preview 1.10 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-10-release/) |
| 2021-08-31 | [1.11] in Windows Terminal Preview<br>[1.10] in Windows Terminal | [Windows Terminal Preview 1.11 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-11-release/) |
| 2021-10-31 | 1.12 in Windows Terminal Preview<br>1.11 in Windows Terminal | |
| 2021-11-30 | 2.0 RC in Windows Terminal Preview<br>2.0 RC in Windows Terminal | |
| 2021-12-31 | [2.0] in Windows Terminal Preview<br>[2.0] in Windows Terminal | |
| 2021-10-20 | [1.12] in Windows Terminal Preview<br>[1.11] in Windows Terminal | [Windows Terminal Preview 1.12 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release/) |
| | 2.0 RC in Windows Terminal Preview<br>2.0 RC in Windows Terminal | |
| | [2.0] in Windows Terminal Preview<br>[2.0] in Windows Terminal | |
## Issue Triage & Prioritization
@ -49,28 +49,32 @@ The following are a list of the key scenarios we're aiming to deliver for Termin
> 👉 Note: There are many other features that don't fit within 2.0, but will be re-assessed and prioritized for 3.0, the plan for which will be published in 2021.
| Priority\* | Scenario | Description/Notes |
| ---------- | -------- | ----------------- |
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564]<br>Specs: [#6720], [#6904]<br>Implementation: [#7283], [#7370], [#8048] |
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193]<br>Implementation: [#6635] |
| 1 | Tab tear-off | The ability to tear a tab out of the current window and spawn a new window or attach it to a separate window.<br><br>Issue: [#1256], [#5000]<br>Spec: [#2080], [#7240] |
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574]<br>Implementation: [#7251] |
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080], [#7414] |
| 1 | Overall theme support | Tab coloring, title bar coloring, pane border coloring, pane border width, definition of what makes a theme<br><br>Issue: [#3327]<br>Spec: [#5772] |
| 1 | Open profile elevated | Configure profiles to always open elevated (if Terminal was run unelevated)<br><br>Issue: [#5000], [#632]<br>Spec: [#8455] |
| 1 | Open tab in existing window | Open new tabs in existing Terminal windows<br><br>Issue: [#5000], [#4472]<br>Spec: [#8135] |
| 1 | Traditional opacity | Have a transparent background without the acrylic blur.<br><br>Issue: [#603] <br>**Current State**: Blocked on WinUI 3.0 |
| 2 | SnapOnOutput, scroll lock | Pause output or scrolling on click.<br><br>Issue: [#980]<br>Spec: [#2529]<br>Implementation: [#6062] |
| 2 | Infinite scrollback | Have an infinite history for the text buffer.<br><br>Issue: [#1410] |
| 2 | Pane management | All issues listed out in the original issue. Some features include pane resizing with mouse, pane zooming, and opening a pane by prompting which profile to use.<br><br>Issue: [#1000] |
| 2 | Theme marketplace | Marketplace for creation and distribution of themes.<br>Dependent on overall theming |
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576]<br>Implementation: [#7515] |
| 2 | Open with multiple tabs | A setting that allows Windows Terminal to launch with a specific tab configuration (not using only command line arguments).<br><br>Issue: [#756] |
| 3 | Open in Windows Terminal | Functionality to right click on a file or folder and select Open in Windows Terminal.<br><br>Issue: [#1060]<br>Implementation: [#6100] |
| 3 | Session restoration | Launch Windows Terminal and the previous session is restored with the proper tab and pane configuration and starting directories.<br><br>Issues: [#961], [#960], [#766] |
| 3 | Quake mode | Provide a quick launch terminal that appears and disappears when a hotkey is pressed.<br><br>Issue: [#653] |
| 3 | Settings migration infrastructure | Migrate people's settings without breaking them. Hand-in-hand with settings UI. |
| 3 | Pointer bindings | Provide settings that can be bound to the mouse.<br><br>Issue: [#1553] |
| Priority\* | Scenario | Description/Notes | State |
| ---------- | -------- | ----------------- | ----- |
| 0 | Settings UI | A user interface that connects to settings.json. This provides a way for people to edit their settings without having to edit a JSON file.<br><br>Issue: [#1564]<br>Specs: [#6720], [#6904]<br>Implementation: [#7283], [#7370], [#8048] | ✔️ |
| 0 | Command palette | A popup menu to list possible actions and commands.<br><br>Issues: [#5400], [#2046]<br>Spec: [#2193]<br>Implementation: [#6635] | ✔️ |
| 1 | Tab tear-off | The ability to tear a tab out of the current window and spawn a new window or attach it to a separate window.<br><br>Issue: [#1256], [#5000]<br>Spec: [#2080], [#7240] | 📝 |
| 1 | Clickable links | Hyperlinking any links that appear in the text buffer. When clicking on the link, the link will open in your default browser.<br><br>Issue: [#574]<br>Implementation: [#7251] | ✔️ |
| 1 | Default terminal | If a command-line application is spawned, it should open in Windows Terminal (if installed) or your preferred terminal<br><br>Issue: [#492]<br>Spec: [#2080], [#7414] | ✔️ |
| 1 | Overall theme support | Tab coloring, title bar coloring, pane border coloring, pane border width, definition of what makes a theme<br><br>Issue: [#3327]<br>Spec: [#5772] | 🦶 |
| 1 | Open profile elevated | Configure profiles to always open elevated (if Terminal was run unelevated)<br><br>Issue: [#5000], [#632]<br>Spec: [#8455] | 📝 |
| 1 | Open tab in existing window | Open new tabs in existing Terminal windows<br><br>Issue: [#5000], [#4472]<br>Spec: [#8135] | ✔️ |
| 1 | Traditional opacity | Have a transparent background without the acrylic blur.<br><br>Issue: [#603] | ✔️ |
| 2 | SnapOnOutput, scroll lock | Pause output or scrolling on click.<br><br>Issue: [#980]<br>Spec: [#2529]<br>Implementation: [#6062] | ✔️ |
| 2 | Infinite scrollback | Have an infinite history for the text buffer.<br><br>Issue: [#1410] | 🦶 |
| 2 | Pane management | All issues listed out in the original issue. Some features include pane resizing with mouse, pane zooming, and opening a pane by prompting which profile to use.<br><br>Issue: [#1000] | 📝 |
| 2 | Theme marketplace | Marketplace for creation and distribution of themes.<br>Dependent on overall theming | 🦶 |
| 2 | Jump list | Show profiles from task bar (on right click)/start menu.<br><br>Issue: [#576]<br>Implementation: [#7515] | ✔️ |
| 2 | Open with multiple tabs | A setting that allows Windows Terminal to launch with a specific tab configuration (not using only command line arguments).<br><br>Issue: [#756] | ✔️ |
| 3 | Open in Windows Terminal | Functionality to right click on a file or folder and select Open in Windows Terminal.<br><br>Issue: [#1060]<br>Implementation: [#6100] | ✔️ |
| 3 | Session restoration | Launch Windows Terminal and the previous session is restored with the proper tab and pane configuration and starting directories.<br><br>Issues: [#961], [#960], [#766] | ✔️ |
| 3 | Quake mode | Provide a quick launch terminal that appears and disappears when a hotkey is pressed.<br><br>Issue: [#653] | ✔️ |
| 3 | Settings migration infrastructure | Migrate people's settings without breaking them. Hand-in-hand with settings UI. | 🦶 |
| 3 | Pointer bindings | Provide settings that can be bound to the mouse.<br><br>Issue: [#1553] | 🦶 |
* 📝: The feature is currently in progress
* ✔️: The feature is complete and shipped in a Preview build
* 🦶: The feature is at risk of being punted to a future release cycle (beyond 2.0)
Feature Notes:
@ -91,6 +95,8 @@ Feature Notes:
[1.9]: https://github.com/microsoft/terminal/milestone/34
[1.10]: https://github.com/microsoft/terminal/milestone/35
[1.11]: https://github.com/microsoft/terminal/milestone/36
[1.12]: https://github.com/microsoft/terminal/milestone/38
[1.13]: https://github.com/microsoft/terminal/milestone/39
[2.0]: https://github.com/microsoft/terminal/milestone/22
[#1564]: https://github.com/microsoft/terminal/issues/1564
[#6720]: https://github.com/microsoft/terminal/pull/6720

201
oss/pcg/LICENSE-APACHE.txt Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

19
oss/pcg/LICENSE-MIT.txt Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
oss/pcg/cgmanifest.json Normal file
View file

@ -0,0 +1,14 @@
{
"Registrations": [
{
"component": {
"type": "git",
"git": {
"repositoryUrl": "https://github.com/imneme/pcg-cpp",
"commitHash": "ffd522e7188bef30a00c74dc7eb9de5faff90092"
}
}
}
],
"Version": 1
}

View file

@ -0,0 +1,82 @@
// PCG Random Number Generation for C++
//
// Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
// and the PCG Project contributors.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//
// Licensed under the Apache License, Version 2.0 (provided in
// LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
// or under the MIT license (provided in LICENSE-MIT.txt and at
// http://opensource.org/licenses/MIT), at your option. This file may not
// be copied, modified, or distributed except according to those terms.
//
// Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
// express or implied. See your chosen license for details.
//
// For additional information about the PCG random number generation scheme,
// visit http://www.pcg-random.org/.
//
// -----------------------------------------------------------------------------
//
// Leonard Hecker <lhecker@microsoft.com>:
// The following contents are an extract of pcg_engines::oneseq_dxsm_64_32
// reduced down to the bare essentials, while retaining base functionality.
namespace pcg_engines {
class oneseq_dxsm_64_32 {
using xtype = uint32_t;
using itype = uint64_t;
itype state_;
static constexpr uint64_t multiplier() {
return 6364136223846793005ULL;
}
static constexpr uint64_t increment() {
return 1442695040888963407ULL;
}
static itype bump(itype state) {
return state * multiplier() + increment();
}
itype base_generate0() {
itype old_state = state_;
state_ = bump(state_);
return old_state;
}
public:
explicit oneseq_dxsm_64_32(itype state = 0xcafef00dd15ea5e5ULL) : state_(bump(state + increment())) {
}
// Returns a value in the interval [0, UINT32_MAX].
xtype operator()() {
constexpr auto xtypebits = uint8_t(sizeof(xtype) * 8);
constexpr auto itypebits = uint8_t(sizeof(itype) * 8);
auto internal = base_generate0();
auto hi = xtype(internal >> (itypebits - xtypebits));
auto lo = xtype(internal);
lo |= 1;
hi ^= hi >> (xtypebits / 2);
hi *= xtype(multiplier());
hi ^= hi >> (3 * (xtypebits / 4));
hi *= lo;
return hi;
}
// Returns a value in the interval [0, upper_bound).
xtype operator()(xtype upper_bound) {
uint32_t threshold = (UINT64_MAX + uint32_t(1) - upper_bound) % upper_bound;
for (;;) {
auto r = operator()();
if (r >= threshold)
return r % upper_bound;
}
}
};
}

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

@ -13,6 +13,15 @@
<EventProvider Id="EventProvider_TerminalRemoting" Name="d6f04aad-629f-539a-77c1-73f5c3e4aa7b" />
<EventProvider Id="EventProvider_TerminalDirectX" Name="c93e739e-ae50-5a14-78e7-f171e947535d" />
<EventProvider Id="EventProvider_TerminalUIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
<!-- Console providers here -->
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Launcher" Name="770aa552-671a-5e97-579b-151709ec0dbd"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Host" Name="fe1ff234-1f09-50a8-d38d-c44fab43e818"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Server" Name="1A541C01-589A-496E-85A7-A9E02170166D"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser" Name="c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Render.VtEngine" Name="c9ba2a95-d3ca-5e19-2bd6-776a0910cb9d"/>
<EventProvider Id="EventProvider-Microsoft.Windows.Console.UIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
<!-- Profile for General Terminal logging -->
<Profile Id="Terminal.Verbose.File" Name="Terminal" Description="Terminal" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_Terminal">
@ -32,5 +41,27 @@
<Profile Id="Terminal.Light.File" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="Terminal.Verbose.Memory" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="Terminal.Light.Memory" Name="Terminal" Description="Terminal" Base="Terminal.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
<!-- Profile for DefTerm logging. Includes some conhost logging. -->
<Profile Id="DefTerm.Verbose.File" Name="DefTerm" Description="DefTerm" LoggingMode="File" DetailLevel="Verbose">
<Collectors>
<EventCollectorId Value="EventCollector_Terminal">
<EventProviders>
<EventProviderId Value="EventProvider_TerminalControl" />
<EventProviderId Value="EventProvider_TerminalConnection" />
<EventProviderId Value="EventProvider_TerminalSettingsModel" />
<EventProviderId Value="EventProvider_TerminalApp" />
<EventProviderId Value="EventProvider_TerminalWin32Host" />
<EventProviderId Value="EventProvider_TerminalRemoting" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Launcher" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Host" />
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Server" />
</EventProviders>
</EventCollectorId>
</Collectors>
</Profile>
<Profile Id="DefTerm.Light.File" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="File" DetailLevel="Light" />
<Profile Id="DefTerm.Verbose.Memory" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="Memory" DetailLevel="Verbose" />
<Profile Id="DefTerm.Light.Memory" Name="DefTerm" Description="DefTerm" Base="DefTerm.Verbose.File" LoggingMode="Memory" DetailLevel="Light" />
</Profiles>
</WindowsPerformanceRecorder>
</WindowsPerformanceRecorder>

View file

@ -12,8 +12,30 @@ static_assert(alignof(TextAttribute) == 2);
// Ensure that we can memcpy() and memmove() the struct for performance.
static_assert(std::is_trivially_copyable_v<TextAttribute>);
BYTE TextAttribute::s_legacyDefaultForeground = 7;
BYTE TextAttribute::s_legacyDefaultBackground = 0;
namespace
{
constexpr std::array<TextColor, 16> s_initLegacyColorMap(const BYTE defaultIndex)
{
std::array<TextColor, 16> legacyColorMap;
for (auto i = 0u; i < legacyColorMap.size(); i++)
{
const auto legacyIndex = TextColor::TransposeLegacyIndex(i);
gsl::at(legacyColorMap, i) = i == defaultIndex ? TextColor{} : TextColor{ legacyIndex, true };
}
return legacyColorMap;
}
BYTE s_legacyDefaultForeground = 7;
BYTE s_legacyDefaultBackground = 0;
BYTE s_ansiDefaultForeground = 7;
BYTE s_ansiDefaultBackground = 0;
}
// These maps allow for an efficient conversion from a legacy attribute index
// to a TextColor with the corresponding ANSI index, also taking into account
// the legacy index values that need to be converted to a default TextColor.
std::array<TextColor, 16> TextAttribute::s_legacyForegroundColorMap = s_initLegacyColorMap(7);
std::array<TextColor, 16> TextAttribute::s_legacyBackgroundColorMap = s_initLegacyColorMap(0);
// Routine Description:
// - Sets the legacy attributes which map to and from the default colors.
@ -23,8 +45,22 @@ BYTE TextAttribute::s_legacyDefaultBackground = 0;
// - None
void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept
{
// First we reset the current default color map entries to what they should
// be for a regular translation from a legacy index to an ANSI TextColor.
gsl::at(s_legacyForegroundColorMap, s_legacyDefaultForeground) = TextColor{ s_ansiDefaultForeground, true };
gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{ s_ansiDefaultBackground, true };
// Then we save the new default attribute values and their corresponding
// ANSI translations. We use the latter values to more efficiently handle
// the "VT Quirk" conversion below.
s_legacyDefaultForeground = defaultAttributes & FG_ATTRS;
s_legacyDefaultBackground = (defaultAttributes & BG_ATTRS) >> 4;
s_ansiDefaultForeground = TextColor::TransposeLegacyIndex(s_legacyDefaultForeground);
s_ansiDefaultBackground = TextColor::TransposeLegacyIndex(s_legacyDefaultBackground);
// Finally we set the new default color map entries.
gsl::at(s_legacyForegroundColorMap, s_legacyDefaultForeground) = TextColor{};
gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{};
}
// Routine Description:
@ -55,13 +91,13 @@ TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const Te
const auto bg{ attribute.GetBackground() };
auto copy{ attribute };
if (fg.IsIndex16() &&
attribute.IsBold() == WI_IsFlagSet(s_legacyDefaultForeground, FOREGROUND_INTENSITY) &&
fg.GetIndex() == (s_legacyDefaultForeground & ~FOREGROUND_INTENSITY))
attribute.IsBold() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY))
{
// We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color.
copy.SetDefaultForeground();
}
if (bg.IsIndex16() && bg.GetIndex() == s_legacyDefaultBackground)
if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground)
{
copy.SetDefaultBackground();
}
@ -92,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

@ -41,8 +41,8 @@ public:
explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ s_LegacyIndexOrDefault(wLegacyAttr & FG_ATTRS, s_legacyDefaultForeground) },
_background{ s_LegacyIndexOrDefault((wLegacyAttr & BG_ATTRS) >> 4, s_legacyDefaultBackground) },
_foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
_background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
_extendedAttrs{ ExtendedAttributes::Normal },
_hyperlinkId{ 0 }
{
@ -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;
@ -167,13 +167,8 @@ public:
}
private:
static constexpr TextColor s_LegacyIndexOrDefault(const BYTE requestedIndex, const BYTE defaultIndex)
{
return requestedIndex == defaultIndex ? TextColor{} : TextColor{ requestedIndex, true };
}
static BYTE s_legacyDefaultForeground;
static BYTE s_legacyDefaultBackground;
static std::array<TextColor, 16> s_legacyForegroundColorMap;
static std::array<TextColor, 16> s_legacyBackgroundColorMap;
uint16_t _wAttrLegacy; // sizeof: 2, alignof: 2
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2

View file

@ -4,6 +4,8 @@
#include "precomp.h"
#include "TextColor.h"
#include <til/bit.h>
// clang-format off
// A table mapping 8-bit RGB colors, in the form RRRGGGBB,
@ -30,7 +32,7 @@ constexpr std::array<BYTE, 256> CompressedRgbToIndex16 = {
// A table mapping indexed colors from the 256-color palette,
// down to one of the 16 colors in the legacy palette.
constexpr std::array<BYTE, 256> Index256ToIndex16 = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15,
0, 1, 1, 1, 9, 9, 2, 1, 1, 1, 1, 1, 2, 2, 3, 3,
3, 3, 2, 2, 11, 11, 3, 3, 10, 10, 11, 11, 11, 11, 10, 10,
10, 10, 11, 11, 5, 5, 5, 5, 1, 1, 8, 8, 1, 1, 9, 9,
@ -137,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.
@ -186,7 +190,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
// the result will be something like 0b00100000.
// 5. Use BitScanForward (bsf) to find the index of the most significant 1 bit.
const auto haystack = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(colorTable.data())); // 1.
const auto needle = _mm256_set1_epi32(__builtin_bit_cast(int, defaultColor)); // 2.
const auto needle = _mm256_set1_epi32(til::bit_cast<int>(defaultColor)); // 2.
const auto result = _mm256_cmpeq_epi32(haystack, needle); // 3.
const auto mask = _mm256_movemask_ps(_mm256_castsi256_ps(result)); // 4.
unsigned long index;
@ -203,7 +207,7 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
// --> the index returned by _BitScanForward must be divided by 2.
const auto haystack1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 0));
const auto haystack2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 4));
const auto needle = _mm_set1_epi32(__builtin_bit_cast(int, defaultColor));
const auto needle = _mm_set1_epi32(til::bit_cast<int>(defaultColor));
const auto result1 = _mm_cmpeq_epi32(haystack1, needle);
const auto result2 = _mm_cmpeq_epi32(haystack2, needle);
const auto result = _mm_packs_epi32(result1, result2); // 3.5
@ -250,11 +254,7 @@ BYTE TextColor::GetLegacyIndex(const BYTE defaultIndex) const noexcept
{
return defaultIndex;
}
else if (IsIndex16())
{
return GetIndex();
}
else if (IsIndex256())
else if (IsIndex16() || IsIndex256())
{
return til::at(Index256ToIndex16, GetIndex());
}

View file

@ -48,6 +48,28 @@ enum class ColorType : BYTE
struct TextColor
{
public:
static constexpr BYTE DARK_BLACK = 0;
static constexpr BYTE DARK_RED = 1;
static constexpr BYTE DARK_GREEN = 2;
static constexpr BYTE DARK_YELLOW = 3;
static constexpr BYTE DARK_BLUE = 4;
static constexpr BYTE DARK_MAGENTA = 5;
static constexpr BYTE DARK_CYAN = 6;
static constexpr BYTE DARK_WHITE = 7;
static constexpr BYTE BRIGHT_BLACK = 8;
static constexpr BYTE BRIGHT_RED = 9;
static constexpr BYTE BRIGHT_GREEN = 10;
static constexpr BYTE BRIGHT_YELLOW = 11;
static constexpr BYTE BRIGHT_BLUE = 12;
static constexpr BYTE BRIGHT_MAGENTA = 13;
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 },
@ -86,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
@ -96,6 +118,16 @@ public:
COLORREF GetRGB() const noexcept;
static constexpr BYTE TransposeLegacyIndex(const size_t index)
{
// When converting a 16-color index in the legacy Windows order to or
// from an ANSI-compatible order, we need to swap the bits in positions
// 0 and 2. We do this by XORing the index with 00000101, but only if
// one (but not both) of those bit positions is set.
const auto oneBitSet = (index ^ (index >> 2)) & 1;
return gsl::narrow_cast<BYTE>(index ^ oneBitSet ^ (oneBitSet << 2));
}
private:
union
{

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()
@ -237,7 +241,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
Log::Comment(L"Foreground legacy default index should map to default text color.");
legacyAttribute = fgLegacyDefault | BACKGROUND_GREEN;
textAttribute.SetDefaultForeground();
textAttribute.SetIndexedBackground256(BACKGROUND_GREEN >> 4);
textAttribute.SetIndexedBackground256(TextColor::DARK_GREEN);
VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute });
Log::Comment(L"Default foreground text color should map back to legacy default index.");
@ -245,7 +249,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
Log::Comment(L"Background legacy default index should map to default text color.");
legacyAttribute = FOREGROUND_GREEN | bgLegacyDefault;
textAttribute.SetIndexedForeground256(FOREGROUND_GREEN);
textAttribute.SetIndexedForeground256(TextColor::DARK_GREEN);
textAttribute.SetDefaultBackground();
VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute });
@ -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(0);
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(2);
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(8);
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

@ -80,7 +80,7 @@ namespace SettingsModelLocalTests
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = gsl::make_span(expectedCampbellTable);
Utils::InitializeCampbellColorTable(campbellSpan);
Utils::InitializeColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0);
for (size_t i = 0; i < expectedCampbellTable.size(); i++)

View file

@ -7,7 +7,9 @@
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "JsonTestClass.h"
#include "TestUtils.h"
#include <defaults.h>
#include <userDefaults.h>
using namespace Microsoft::Console;
using namespace WEX::Logging;
@ -70,6 +72,7 @@ namespace SettingsModelLocalTests
TEST_METHOD(TestCloneInheritanceTree);
TEST_METHOD(TestValidDefaults);
TEST_METHOD(TestInheritedCommand);
TEST_METHOD(LoadFragmentsWithMultipleUpdates);
private:
static winrt::com_ptr<implementation::CascadiaSettings> createSettings(const std::string_view& userJSON)
@ -1979,4 +1982,34 @@ namespace SettingsModelLocalTests
VERIFY_IS_NULL(actualKeyChord);
}
}
// This test ensures GH#11597 doesn't regress.
void DeserializationTests::LoadFragmentsWithMultipleUpdates()
{
static constexpr std::wstring_view fragmentSource{ L"fragment" };
static constexpr std::string_view fragmentJson{ R"({
"profiles": [
{
"updates": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"cursorShape": "filledBox"
},
{
"updates": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"cursorShape": "filledBox"
},
{
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe"
}
]
})" };
implementation::SettingsLoader loader{ std::string_view{}, DefaultJson };
loader.MergeInboxIntoUserSettings();
loader.MergeFragmentIntoUserSettings(winrt::hstring{ fragmentSource }, fragmentJson);
loader.FinalizeLayering();
VERIFY_IS_FALSE(loader.duplicateProfile);
VERIFY_ARE_EQUAL(3u, loader.userSettings.profiles.size());
}
}

View file

@ -272,20 +272,30 @@ namespace SettingsModelLocalTests
void ProfileTests::DuplicateProfileTest()
{
static constexpr std::string_view userProfiles{ R"({
"profiles": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"backgroundImage": "file:///some/path",
"hidden": false,
}
]
"profiles": {
"defaults": {
"font": {
"size": 123
}
},
"list": [
{
"name": "profile0",
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"backgroundImage": "file:///some/path",
"hidden": false,
}
]
}
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(userProfiles);
const auto profile = settings->AllProfiles().GetAt(0);
const auto duplicatedProfile = settings->DuplicateProfile(profile);
// GH#11392: Ensure duplicated profiles properly inherit the base layer, even for nested objects.
VERIFY_ARE_EQUAL(123, duplicatedProfile.FontInfo().FontSize());
duplicatedProfile.Guid(profile.Guid());
duplicatedProfile.Name(profile.Name());

View file

@ -97,6 +97,7 @@ namespace SettingsModelLocalTests
"confirmCloseAllTabs": true,
"largePasteWarning": true,
"multiLinePasteWarning": true,
"trimPaste": true,
"experimental.input.forceVT": false,
"experimental.rendering.forceFullRepaint": false,

View file

@ -3,6 +3,8 @@
#include "pch.h"
#include <til/rand.h>
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../TerminalSettingsModel/TerminalSettings.h"
#include "TestUtils.h"
@ -34,14 +36,12 @@ namespace SettingsModelLocalTests
END_TEST_CLASS()
TEST_METHOD(TryCreateWinRTType);
TEST_METHOD(TestTerminalArgsForBinding);
TEST_METHOD(CommandLineToArgvW);
TEST_METHOD(GetProfileForArgsWithCommandline);
TEST_METHOD(MakeSettingsForProfile);
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
TEST_METHOD(TestLayerProfileOnColorScheme);
TEST_METHOD(TestCommandlineToTitlePromotion);
TEST_CLASS_SETUP(ClassSetup)
@ -60,6 +60,139 @@ namespace SettingsModelLocalTests
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
}
// CascadiaSettings::_normalizeCommandLine abuses some aspects from CommandLineToArgvW
// to simplify the implementation. It assumes that all arguments returned by
// CommandLineToArgvW are returned back to back in memory as "arg1\0arg2\0arg3\0...".
// This test ensures CommandLineToArgvW doesn't change just to be sure.
void TerminalSettingsTests::CommandLineToArgvW()
{
pcg_engines::oneseq_dxsm_64_32 rng{ til::gen_random<uint64_t>() };
const auto expectedArgc = static_cast<int>(rng(16) + 1);
std::wstring expectedArgv;
std::wstring input;
// We generate up to 16 arguments. Each argument is up to 64 chars long, is quoted
// (2 chars, only applies to the input) and separated by a whitespace (1 char).
expectedArgv.reserve(expectedArgc * 65);
input.reserve(expectedArgc * 67);
for (int i = 0; i < expectedArgc; ++i)
{
const bool useQuotes = static_cast<bool>(rng(2));
const auto count = static_cast<size_t>(rng(64));
const auto ch = static_cast<wchar_t>(rng('z' - 'a' + 1) + 'a');
if (i != 0)
{
expectedArgv.push_back(L'\0');
input.push_back(L' ');
}
if (useQuotes)
{
input.push_back(L'"');
}
expectedArgv.append(count, ch);
input.append(count, ch);
if (useQuotes)
{
input.push_back(L'"');
}
}
int argc;
wil::unique_hlocal_ptr<PWSTR[]> argv{ ::CommandLineToArgvW(input.c_str(), &argc) };
VERIFY_ARE_EQUAL(expectedArgc, argc);
VERIFY_IS_NOT_NULL(argv);
const auto lastArg = argv[argc - 1];
const auto beg = argv[0];
const auto end = lastArg + wcslen(lastArg);
VERIFY_IS_GREATER_THAN(end, beg);
VERIFY_ARE_EQUAL(expectedArgv.size(), static_cast<size_t>(end - beg));
VERIFY_ARE_EQUAL(0, memcmp(beg, expectedArgv.data(), expectedArgv.size()));
}
void TerminalSettingsTests::GetProfileForArgsWithCommandline()
{
// I'm exclusively using cmd.exe as I know exactly where it resides at.
static constexpr std::string_view settingsJson{ R"({
"profiles": {
"defaults": {
"historySize": 123
},
"list": [
{
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
"commandline": "%SystemRoot%\\System32\\cmd.exe"
},
{
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A"
},
{
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A /B"
},
{
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A /C",
"connectionType": "{9a9977a7-1fe0-49c0-b6c0-13a0cd1c98a1}"
}
]
}
})" };
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
struct TestCase
{
std::wstring_view input;
int expected;
};
static constexpr std::array testCases{
// Base test.
TestCase{ L"cmd.exe", 0 },
// SearchPathW() normalization + case insensitive matching.
TestCase{ L"cmd.exe /a", 1 },
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A", 1 },
// Test that we don't pick the equally long but different "/A /B" variant.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
// Test that we don't pick the shorter "/A" variant,
// but do pick the shorter "/A /B" variant for longer inputs.
TestCase{ L"cmd.exe /A /B", 2 },
TestCase{ L"cmd.exe /A /B /C", 2 },
// Ignore profiles with a connection type, like the Azure cloud shell.
// Instead it should pick any other prefix.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
// Return base layer profile for missing profiles.
TestCase{ L"C:\\Windows\\regedit.exe", -1 },
};
for (const auto& testCase : testCases)
{
NewTerminalArgs args;
args.Commandline(testCase.input);
const auto profile = settings->GetProfileForArgs(args);
VERIFY_IS_NOT_NULL(profile);
if (testCase.expected < 0)
{
VERIFY_ARE_EQUAL(123, profile.HistorySize());
}
else
{
GUID expectedGUID{ 0x6239a42c, static_cast<uint16_t>(0x1111 * testCase.expected), 0x49a3, { 0x80, 0xbd, 0xe8, 0xfd, 0xd0, 0x45, 0x18, 0x5c } };
VERIFY_ARE_EQUAL(expectedGUID, static_cast<const GUID&>(profile.Guid()));
}
}
}
void TerminalSettingsTests::TestTerminalArgsForBinding()
{
static constexpr std::string_view settingsJson{ R"(

View file

@ -508,7 +508,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@ -526,7 +526,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
result = RunOnUIThread([&page]() {
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@ -844,7 +844,7 @@ namespace TerminalAppLocalTests
// | 1 | 2 |
// | | |
// -------------------
page->_SplitPane(SplitDirection::Right, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr));
secondId = tab->_activePane->Id().value();
});
Sleep(250);
@ -862,7 +862,7 @@ namespace TerminalAppLocalTests
// | 3 | |
// | | |
// -------------------
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
// Split again to make the 3rd tab
thirdId = tab->_activePane->Id().value();
@ -882,7 +882,7 @@ namespace TerminalAppLocalTests
// | 3 | 4 |
// | | |
// -------------------
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr);
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
fourthId = tab->_activePane->Id().value();
});

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
@ -977,7 +977,7 @@ void HwndTerminal::_StringPaste(const wchar_t* const pData) noexcept
CATCH_LOG();
}
COORD HwndTerminal::GetFontSize() const
COORD HwndTerminal::GetFontSize() const noexcept
{
return _actualFont.GetSize();
}

View file

@ -128,7 +128,7 @@ private:
void _SendCharEvent(wchar_t ch, WORD scanCode, WORD flags) noexcept;
// Inherited via IControlAccessibilityInfo
COORD GetFontSize() const override;
COORD GetFontSize() const noexcept override;
RECT GetBounds() const noexcept override;
double GetScaleFactor() const noexcept override;
void ChangeViewport(const SMALL_RECT NewWindow) override;

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

@ -174,10 +174,9 @@ namespace winrt::TerminalApp::implementation
else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>())
{
_SplitPane(realArgs.SplitDirection(),
realArgs.SplitMode(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
realArgs.TerminalArgs());
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
args.Handled(true);
}
}
@ -556,7 +555,7 @@ namespace winrt::TerminalApp::implementation
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(
TerminalPage::ConvertExecuteCommandlineToActions(realArgs)));
if (_startupActions.Size() != 0)
if (actions.Size() != 0)
{
actionArgs.Handled(true);
ProcessStartupActions(actions, false);

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()]() {
@ -334,6 +304,9 @@ namespace winrt::TerminalApp::implementation
_RefreshThemeRoutine();
_ApplyStartupTaskStateChange();
auto args = winrt::make_self<SystemMenuChangeArgs>(RS_(L"SettingsMenuItem"), SystemMenuChangeAction::Add, SystemMenuItemHandler(this, &AppLogic::_OpenSettingsUI));
_SystemMenuChangeRequestedHandlers(*this, *args);
TraceLoggingWrite(
g_hTerminalAppProvider,
"AppCreated",
@ -375,6 +348,8 @@ namespace winrt::TerminalApp::implementation
co_return ContentDialogResult::None;
}
_dialog = dialog;
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
// xaml tree somehow.
@ -412,6 +387,16 @@ namespace winrt::TerminalApp::implementation
// be released so another can be shown
}
// Method Description:
// - Dismiss the (only) visible ContentDialog
void AppLogic::DismissDialog()
{
if (auto localDialog = std::exchange(_dialog, nullptr))
{
localDialog.Hide();
}
}
// Method Description:
// - Displays a dialog for errors found while loading or validating the
// settings. Uses the resources under the provided title and content keys
@ -895,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,
@ -905,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();
}
@ -1039,6 +1037,11 @@ namespace winrt::TerminalApp::implementation
_SettingsChangedHandlers(*this, nullptr);
}
void AppLogic::_OpenSettingsUI()
{
_root->OpenSettingsUI();
}
// Method Description:
// - Returns a pointer to the global shared settings.
[[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept
@ -1545,6 +1548,11 @@ namespace winrt::TerminalApp::implementation
return _root->IsQuakeWindow();
}
void AppLogic::RequestExitFullscreen()
{
_root->SetFullscreen(false);
}
bool AppLogic::GetMinimizeToNotificationArea()
{
if constexpr (Feature_NotificationIcon::IsEnabled())

View file

@ -5,6 +5,7 @@
#include "AppLogic.g.h"
#include "FindTargetWindowResult.g.h"
#include "SystemMenuChangeArgs.g.h"
#include "Jumplist.h"
#include "LanguageProfileNotifier.h"
#include "TerminalPage.h"
@ -35,6 +36,17 @@ namespace winrt::TerminalApp::implementation
FindTargetWindowResult(id, L""){};
};
struct SystemMenuChangeArgs : SystemMenuChangeArgsT<SystemMenuChangeArgs>
{
WINRT_PROPERTY(winrt::hstring, Name, L"");
WINRT_PROPERTY(SystemMenuChangeAction, Action, SystemMenuChangeAction::Add);
WINRT_PROPERTY(SystemMenuItemHandler, Handler, nullptr);
public:
SystemMenuChangeArgs(const winrt::hstring& name, SystemMenuChangeAction action, SystemMenuItemHandler handler = nullptr) :
_Name{ name }, _Action{ action }, _Handler{ handler } {};
};
struct AppLogic : AppLogicT<AppLogic, IInitializeWithWindow>
{
public:
@ -79,6 +91,7 @@ namespace winrt::TerminalApp::implementation
void SetPersistedLayoutIdx(const uint32_t idx);
void SetNumberOfOpenWindows(const uint64_t num);
bool IsQuakeWindow() const noexcept;
void RequestExitFullscreen();
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
bool CenterOnLaunch();
@ -106,12 +119,14 @@ namespace winrt::TerminalApp::implementation
bool GetShowTitleInTitlebar();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
void DismissDialog();
Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> GlobalHotkeys();
// -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
private:
bool _isUwp{ false };
@ -132,6 +147,7 @@ namespace winrt::TerminalApp::implementation
uint64_t _numOpenWindows{ 0 };
std::shared_mutex _dialogLock;
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog;
::TerminalApp::AppCommandlineArgs _appArgs;
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
@ -161,6 +177,7 @@ namespace winrt::TerminalApp::implementation
void _RegisterSettingsChange();
fire_and_forget _DispatchReloadSettings();
void _ReloadSettings();
void _OpenSettingsUI();
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);

View file

@ -19,6 +19,20 @@ namespace TerminalApp
String WindowName { get; };
};
delegate void SystemMenuItemHandler();
enum SystemMenuChangeAction
{
Add = 0,
Remove = 1
};
[default_interface] runtimeclass SystemMenuChangeArgs {
String Name { get; };
SystemMenuChangeAction Action { get; };
SystemMenuItemHandler Handler { get; };
};
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
{
AppLogic();
@ -60,6 +74,7 @@ namespace TerminalApp
void SetPersistedLayoutIdx(UInt32 idx);
void SetNumberOfOpenWindows(UInt64 num);
void RenameFailed();
void RequestExitFullscreen();
Boolean IsQuakeWindow();
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
@ -91,6 +106,7 @@ namespace TerminalApp
// See IDialogPresenter and TerminalPage's DialogPresenter for more
// information.
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
void DismissDialog();
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
@ -109,5 +125,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
}
}

View file

@ -21,8 +21,22 @@ namespace winrt::Microsoft::TerminalApp::implementation
}
void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) {}
~DebugInputTapConnection() = default;
void Start()
winrt::fire_and_forget Start()
{
// GH#11282: It's possible that we're about to be started, _before_
// our paired connection is started. Both will get Start()'ed when
// their owning TermControl is finally laid out. However, if we're
// started first, then we'll immediately start printing to the other
// control as well, which might not have initialized yet. If we do
// that, we'll explode.
//
// Instead, wait here until the other connection is started too,
// before actually starting the connection to the client app. This
// will ensure both controls are initialized before the client app
// is.
co_await winrt::resume_background();
_pairedTap->_start.wait();
_wrappedConnection.Start();
}
void WriteInput(hstring const& data)
@ -59,6 +73,9 @@ namespace winrt::Microsoft::TerminalApp::implementation
void DebugTapConnection::Start()
{
// presume the wrapped connection is started.
// This is explained in the comment for GH#11282 above.
_start.count_down();
}
void DebugTapConnection::WriteInput(hstring const& data)

View file

@ -5,6 +5,7 @@
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
#include "../../inc/cppwinrt_utils.h"
#include <til/latch.h>
namespace winrt::Microsoft::TerminalApp::implementation
{
@ -36,6 +37,8 @@ namespace winrt::Microsoft::TerminalApp::implementation
winrt::weak_ref<Microsoft::Terminal::TerminalConnection::ITerminalConnection> _wrappedConnection;
winrt::weak_ref<Microsoft::Terminal::TerminalConnection::ITerminalConnection> _inputSide;
til::latch _start{ 1 };
friend class DebugInputTapConnection;
};
}

View file

@ -2351,35 +2351,32 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
}
// Method Description:
// - Split the focused pane in our tree of panes, and place the given
// TermControl into the newly created pane. If we're the focused pane, then
// we'll create two new children, and place them side-by-side in our Grid.
// - The same as above, except this takes in the pane directly instead of a
// profile and control to make a pane with
// Arguments:
// - splitType: what type of split we want to create.
// - profile: The profile to associate with the newly created pane.
// - control: A TermControl to use in the new pane.
// - splitSize: the desired size of the split
// - newPane: the new pane
// Return Value:
// - The two newly created Panes, with the original pane first
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitDirection splitType,
const float splitSize,
const Profile& profile,
const TermControl& control)
std::shared_ptr<Pane> newPane)
{
if (!_lastActive)
{
if (_firstChild && _firstChild->_HasFocusedChild())
{
return _firstChild->Split(splitType, splitSize, profile, control);
return _firstChild->Split(splitType, splitSize, newPane);
}
else if (_secondChild && _secondChild->_HasFocusedChild())
{
return _secondChild->Split(splitType, splitSize, profile, control);
return _secondChild->Split(splitType, splitSize, newPane);
}
return { nullptr, nullptr };
}
auto newPane = std::make_shared<Pane>(profile, control);
return _Split(splitType, splitSize, newPane);
}

View file

@ -110,8 +110,7 @@ public:
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control);
std::shared_ptr<Pane> pane);
bool ToggleSplitOrientation();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,

View file

@ -718,10 +718,17 @@
<data name="CloseOnExitInfoBar.Message" xml:space="preserve">
<value>Termination behavior can be configured in advanced profile settings.</value>
</data>
<data name="SetAsDefaultInfoBar.Message" xml:space="preserve">
<value>Windows Terminal can be set as the default terminal application in your settings.</value>
</data>
<data name="InfoBarDismissButton.Content" xml:space="preserve">
<value>Don't show again</value>
</data>
<data name="ElevationShield.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>This Terminal window is running as Admin</value>
</data>
<data name="SetAsDefaultTip_OpenSettingsLink.Content" xml:space="preserve">
<value>Open Settings</value>
<comment>This is a call-to-action hyperlink; it will open the settings.</comment>
</data>
</root>

View file

@ -68,7 +68,7 @@ namespace winrt::TerminalApp::implementation
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
_CreateNewTabWithProfileAndSettings(profile, settings, existingConnection);
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
const uint32_t tabCount = _tabs.Size();
const bool usedManualProfile = (newTerminalArgs != nullptr) &&
@ -244,58 +244,6 @@ namespace winrt::TerminalApp::implementation
_InitializeTab(newTabImpl);
}
// Method Description:
// - Creates a new tab with the given settings. If the tab bar is not being
// currently displayed, it will be shown.
// Arguments:
// - profile: profile settings for this connection
// - settings: the TerminalSettings object to use to create the TerminalControl with.
// - existingConnection: optionally receives a connection from the outside world instead of attempting to create one
void TerminalPage::_CreateNewTabWithProfileAndSettings(const Profile& profile, const TerminalSettingsCreateResult& settings, TerminalConnection::ITerminalConnection existingConnection)
{
// Initialize the new tab
// Create a connection based on the values in our settings object if we weren't given one.
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, settings.DefaultSettings());
// If we had an `existingConnection`, then this is an inbound handoff from somewhere else.
// We need to tell it about our size information so it can match the dimensions of what
// we are about to present.
if (existingConnection)
{
connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols());
}
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
if (_settings.GlobalSettings().DebugFeaturesEnabled())
{
const CoreWindow window = CoreWindow::GetForCurrentThread();
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (bothAltsPressed)
{
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
}
}
// Give term control a child of the settings so that any overrides go in the child
// This way, when we do a settings reload we just update the parent and the overrides remain
auto term = _InitControl(settings, connection);
auto newTabImpl = winrt::make_self<TerminalTab>(profile, term);
_RegisterTerminalEvents(term);
_InitializeTab(newTabImpl);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
auto newControl = _InitControl(settings, debugConnection);
_RegisterTerminalEvents(newControl);
// Split (auto) with the debug tap.
newTabImpl->SplitPane(SplitDirection::Automatic, 0.5f, profile, newControl);
}
}
// Method Description:
// - Get the icon of the currently focused terminal control, and set its
// tab's icon to that icon.
@ -365,28 +313,14 @@ namespace winrt::TerminalApp::implementation
// In the future, it may be preferable to just duplicate the
// current control's live settings (which will include changes
// made through VT).
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
if (auto profile = tab.GetFocusedProfile())
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
const auto settingsCreateResult{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
if (auto newTab{ _GetFocusedTabImpl() })
{
settingsCreateResult.DefaultSettings().StartingDirectory(workingDirectory);
}
_CreateNewTabWithProfileAndSettings(profile, settingsCreateResult);
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
if (auto newTab{ _GetFocusedTabImpl() })
{
newTab->SetTabText(runtimeTabText);
}
newTab->SetTabText(runtimeTabText);
}
}
}
@ -402,7 +336,7 @@ namespace winrt::TerminalApp::implementation
try
{
_SetFocusedTab(tab);
_SplitPane(tab, SplitDirection::Automatic, SplitType::Duplicate);
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
}
CATCH_LOG();
}

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 });
@ -218,7 +218,7 @@ namespace winrt::TerminalApp::implementation
_RegisterActionCallbacks();
// Hook up inbound connection event handler
TerminalConnection::ConptyConnection::NewConnection({ this, &TerminalPage::_OnNewConnection });
ConptyConnection::NewConnection({ this, &TerminalPage::_OnNewConnection });
//Event Bindings (Early)
_newTabButton.Click([weakThis{ get_weak() }](auto&&, auto&&) {
@ -287,6 +287,8 @@ namespace winrt::TerminalApp::implementation
_defaultPointerCursor = CoreWindow::GetForCurrentThread().PointerCursor();
}
CATCH_LOG();
ShowSetAsDefaultInfoBar();
}
// Method Description;
@ -298,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;
}
@ -848,14 +847,7 @@ namespace winrt::TerminalApp::implementation
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (altPressed && !debugTap)
{
this->_SplitPane(SplitDirection::Automatic,
SplitType::Manual,
0.5f,
newTerminalArgs);
}
else if (shiftPressed && !debugTap)
if (shiftPressed && !debugTap)
{
// Manually fill in the evaluated profile.
if (newTerminalArgs.ProfileIndex() != nullptr)
@ -871,7 +863,17 @@ namespace winrt::TerminalApp::implementation
}
else
{
LOG_IF_FAILED(this->_OpenNewTab(newTerminalArgs));
const auto newPane = _MakePane(newTerminalArgs);
if (altPressed && !debugTap)
{
this->_SplitPane(SplitDirection::Automatic,
0.5f,
newPane);
}
else
{
_CreateNewTabFromPane(newPane);
}
}
}
@ -1036,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)
{
}
}
@ -1483,18 +1609,15 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Split the focused pane either horizontally or vertically, and place the
// given TermControl into the newly created pane.
// given pane accordingly in the tree
// Arguments:
// - newPane: the pane to add to our tree of panes
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane.
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
// - splitSize: the size of the split
void TerminalPage::_SplitPane(const SplitDirection splitDirection,
const SplitType splitMode,
const float splitSize,
const NewTerminalArgs& newTerminalArgs)
std::shared_ptr<Pane> newPane)
{
const auto focusedTab{ _GetFocusedTabImpl() };
@ -1504,101 +1627,52 @@ namespace winrt::TerminalApp::implementation
return;
}
_SplitPane(*focusedTab, splitDirection, splitMode, splitSize, newTerminalArgs);
_SplitPane(*focusedTab, splitDirection, splitSize, newPane);
}
// Method Description:
// - Split the focused pane of the given tab, either horizontally or vertically, and place the
// given TermControl into the newly created pane.
// given pane accordingly
// Arguments:
// - tab: The tab that is going to be split.
// - newPane: the pane to add to our tree of panes
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane.
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
// - splitSize: the size of the split
void TerminalPage::_SplitPane(TerminalTab& tab,
const SplitDirection splitDirection,
const SplitType splitMode,
const float splitSize,
const NewTerminalArgs& newTerminalArgs)
std::shared_ptr<Pane> newPane)
{
try
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
auto realSplitType = splitDirection;
if (realSplitType == SplitDirection::Automatic)
{
TerminalSettingsCreateResult controlSettings{ nullptr };
Profile profile{ nullptr };
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
}
if (splitMode == SplitType::Duplicate)
const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
}
_UnZoomIfNeeded();
tab.SplitPane(realSplitType, splitSize, newPane);
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
// the control here instead.
if (_startupState == StartupState::Initialized)
{
if (const auto control = _GetActiveControl())
{
profile = tab.GetFocusedProfile();
if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}
}
// TODO: GH#5047 - In the future, we should get the Profile of
// the focused pane, and use that to build a new instance of the
// settings so we can duplicate this tab/pane.
//
// Currently, if the profile doesn't exist anymore in our
// settings, we'll silently do nothing.
//
// In the future, it will be preferable to just duplicate the
// current control's settings, but we can't do that currently,
// because we won't be able to create a new instance of the
// connection without keeping an instance of the original Profile
// object around.
}
if (!profile)
{
profile = _settings.GetProfileForArgs(newTerminalArgs);
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
auto realSplitType = splitDirection;
if (realSplitType == SplitDirection::Automatic)
{
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
}
auto newControl = _InitControl(controlSettings, controlConnection);
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(newControl);
_UnZoomIfNeeded();
tab.SplitPane(realSplitType, splitSize, profile, newControl);
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
// the control here instead.
if (_startupState == StartupState::Initialized)
{
_GetActiveControl().Focus(FocusState::Programmatic);
control.Focus(FocusState::Programmatic);
}
}
CATCH_LOG();
}
// Method Description:
@ -1867,6 +1941,22 @@ namespace winrt::TerminalApp::implementation
}
}
if (_settings.GlobalSettings().TrimPaste())
{
std::wstring_view textView{ text };
const auto pos = textView.find_last_not_of(L"\t\n\v\f\r ");
if (pos == textView.npos)
{
// Text is all white space, nothing to paste
co_return;
}
else if (const auto toRemove = textView.size() - 1 - pos; toRemove > 0)
{
textView.remove_suffix(toRemove);
text = { textView };
}
}
bool warnMultiLine = _settings.GlobalSettings().WarnAboutMultiLinePaste();
if (warnMultiLine)
{
@ -2090,7 +2180,7 @@ namespace winrt::TerminalApp::implementation
{
if (target == SettingsTarget::SettingsUI)
{
_OpenSettingsUI();
OpenSettingsUI();
}
else
{
@ -2167,6 +2257,96 @@ namespace winrt::TerminalApp::implementation
return term;
}
// Method Description:
// - Creates a pane and returns a shared_ptr to it
// - The caller should handle where the pane goes after creation,
// either to split an already existing pane or to create a new tab with it
// Arguments:
// - newTerminalArgs: an object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
// - duplicate: a boolean to indicate whether the pane we create should be
// a duplicate of the currently focused pane
// - existingConnection: optionally receives a connection from the outside
// world instead of attempting to create one
std::shared_ptr<Pane> TerminalPage::_MakePane(const NewTerminalArgs& newTerminalArgs, const bool duplicate, TerminalConnection::ITerminalConnection existingConnection)
{
TerminalSettingsCreateResult controlSettings{ nullptr };
Profile profile{ nullptr };
if (duplicate)
{
const auto focusedTab{ _GetFocusedTabImpl() };
if (focusedTab)
{
profile = focusedTab->GetFocusedProfile();
if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}
}
}
}
if (!profile)
{
profile = _settings.GetProfileForArgs(newTerminalArgs);
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
if (existingConnection)
{
connection.Resize(controlSettings.DefaultSettings().InitialRows(), controlSettings.DefaultSettings().InitialCols());
}
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
if (_settings.GlobalSettings().DebugFeaturesEnabled())
{
const CoreWindow window = CoreWindow::GetForCurrentThread();
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (bothAltsPressed)
{
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
}
}
const auto control = _InitControl(controlSettings, connection);
_RegisterTerminalEvents(control);
auto resultPane = std::make_shared<Pane>(profile, control);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
auto newControl = _InitControl(controlSettings, debugConnection);
_RegisterTerminalEvents(newControl);
// Split (auto) with the debug tap.
auto debugPane = std::make_shared<Pane>(profile, newControl);
// Since we're doing this split directly on the pane (instead of going through TerminalTab,
// we need to handle the panes 'active' states
// Set the pane we're splitting to active (otherwise Split will not do anything)
resultPane->SetActive();
auto [original, _] = resultPane->Split(SplitDirection::Automatic, 0.5f, debugPane);
// Set the non-debug pane as active
resultPane->ClearActive();
original->SetActive();
}
return resultPane;
}
// Method Description:
// - Hook up keybindings, and refresh the UI of the terminal.
// This includes update the settings of all the tabs according
@ -2476,9 +2656,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::ToggleFullscreen()
{
_isFullscreen = !_isFullscreen;
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
SetFullscreen(!_isFullscreen);
}
// Method Description:
@ -2695,52 +2873,51 @@ namespace winrt::TerminalApp::implementation
return _isAlwaysOnTop;
}
HRESULT TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
void TerminalPage::SetFullscreen(bool newFullscreen)
{
if (_isFullscreen == newFullscreen)
{
return;
}
_isFullscreen = newFullscreen;
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
}
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
{
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
// and wait on it hence the locking mechanism.
if (Dispatcher().HasThreadAccess())
{
try
{
NewTerminalArgs newTerminalArgs{};
// TODO GH#10952: When we pass the actual commandline (or originating application), the
// settings model can choose the right settings based on command matching, or synthesize
// a profile from the registry/link settings (TODO GH#9458).
// TODO GH#9458: Get and pass the LNK/EXE filenames.
// Passing in a commandline forces GetProfileForArgs to use Base Layer instead of Default Profile;
// in the future, it can make a better decision based on the value we pull out of the process handle.
// TODO GH#5047: When we hang on to the N.T.A., try not to spawn "default... .exe" :)
newTerminalArgs.Commandline(L"default-terminal-invocation-placeholder");
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
_CreateNewTabWithProfileAndSettings(profile, settings, connection);
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
}
CATCH_RETURN();
return S_OK;
}
else
if (!Dispatcher().HasThreadAccess())
{
til::latch latch{ 1 };
HRESULT finalVal = S_OK;
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
// Re-running ourselves under the dispatcher will cause us to take the first branch above.
finalVal = _OnNewConnection(connection);
latch.count_down();
});
latch.wait();
return finalVal;
}
try
{
NewTerminalArgs newTerminalArgs;
newTerminalArgs.Commandline(connection.Commandline());
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection));
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
return S_OK;
}
CATCH_RETURN()
}
// Method Description:
@ -2750,7 +2927,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
void TerminalPage::_OpenSettingsUI()
void TerminalPage::OpenSettingsUI()
{
// If we're holding the settings tab's switch command, don't create a new one, switch to the existing one.
if (!_settingsTab)
@ -2893,6 +3070,30 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Displays a info popup guiding the user into setting their default terminal.
void TerminalPage::ShowSetAsDefaultInfoBar() const
{
if (!CascadiaSettings::IsDefaultTerminalAvailable() || _IsMessageDismissed(InfoBarMessage::SetAsDefault))
{
return;
}
// If the user has already configured any terminal for hand-off we
// shouldn't inform them again about the possibility to do so.
if (CascadiaSettings::IsDefaultTerminalSet())
{
_DismissMessage(InfoBarMessage::SetAsDefault);
return;
}
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipPresented", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
infoBar.IsOpen(true);
}
}
// Function Description:
// - Helper function to get the OS-localized name for the "Touch Keyboard
// and Handwriting Panel Service". If we can't open up the service for any
@ -3313,6 +3514,40 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Persists the user's choice not to show the information bar warning about "Windows Terminal can be set as your default terminal application"
// Then hides this information buffer.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_SetAsDefaultDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
_DismissMessage(InfoBarMessage::SetAsDefault);
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipDismissed", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_FocusCurrentTab(true);
}
// Method Description:
// - Dismisses the Default Terminal tip and opens the settings.
void TerminalPage::_SetAsDefaultOpenSettingsHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
OpenSettingsUI();
}
// Method Description:
// - Checks whether information bar message was dismissed earlier (in the application state)
// Arguments:
@ -3342,13 +3577,20 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::_DismissMessage(const InfoBarMessage& message)
{
auto dismissedMessages = ApplicationState::SharedInstance().DismissedMessages();
if (!dismissedMessages)
const auto applicationState = ApplicationState::SharedInstance();
std::vector<InfoBarMessage> messages;
if (const auto values = applicationState.DismissedMessages())
{
dismissedMessages = winrt::single_threaded_vector<InfoBarMessage>();
messages.resize(values.Size());
values.GetMany(0, messages);
}
dismissedMessages.Append(message);
ApplicationState::SharedInstance().DismissedMessages(dismissedMessages);
if (std::none_of(messages.begin(), messages.end(), [&](const auto& m) { return m == message; }))
{
messages.emplace_back(message);
}
applicationState.DismissedMessages(std::move(messages));
}
}

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
{
@ -83,6 +88,7 @@ namespace winrt::TerminalApp::implementation
bool FocusMode() const;
bool Fullscreen() const;
bool AlwaysOnTop() const;
void SetFullscreen(bool);
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
@ -95,6 +101,7 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::TaskbarState TaskbarState() const;
void ShowKeyboardServiceWarning() const;
void ShowSetAsDefaultInfoBar() const;
winrt::hstring KeyboardServiceDisabledText();
winrt::fire_and_forget IdentifyWindow();
@ -120,6 +127,8 @@ namespace winrt::TerminalApp::implementation
bool IsQuakeWindow() const noexcept;
bool IsElevated() const noexcept;
void OpenSettingsUI();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
// -------------------------------- WinRT Events ---------------------------------
@ -208,7 +217,6 @@ namespace winrt::TerminalApp::implementation
void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane);
void _CreateNewTabWithProfileAndSettings(const Microsoft::Terminal::Settings::Model::Profile& profile, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
winrt::fire_and_forget _OpenNewWindow(const bool elevate, const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
@ -222,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();
@ -296,14 +306,12 @@ namespace winrt::TerminalApp::implementation
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
const float splitSize = 0.5f,
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
const float splitSize,
std::shared_ptr<Pane> newPane);
void _SplitPane(TerminalTab& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
const float splitSize = 0.5f,
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
const float splitSize,
std::shared_ptr<Pane> newPane);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation();
@ -350,6 +358,10 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
const bool duplicate = false,
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _RefreshUIForSettingsReload();
void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor);
@ -365,8 +377,6 @@ namespace winrt::TerminalApp::implementation
void _UnZoomIfNeeded();
void _OpenSettingsUI();
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
static uint32_t _ReadSystemRowsToScroll();
@ -387,7 +397,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
std::vector<std::function<void()>> _restorePreviewFuncs{};
HRESULT _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
HRESULT _OnNewConnection(const winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection& connection);
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
void _WindowRenamerActionClick(const IInspectable& sender, const IInspectable& eventArgs);
@ -403,6 +413,8 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
void _SetAsDefaultDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);

View file

@ -15,6 +15,7 @@
<Grid x:Name="Root"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
@ -22,8 +23,50 @@
<local:TabRowControl x:Name="TabRow"
Grid.Row="0" />
<StackPanel Grid.Row="1">
<mux:InfoBar x:Name="KeyboardServiceWarningInfoBar"
x:Load="False"
IsClosable="True"
IsIconVisible="True"
IsOpen="False"
Message="{x:Bind KeyboardServiceDisabledText, Mode=OneWay}"
Severity="Warning">
<mux:InfoBar.ActionButton>
<Button x:Uid="InfoBarDismissButton"
Click="_KeyboardServiceWarningInfoDismissHandler" />
</mux:InfoBar.ActionButton>
</mux:InfoBar>
<mux:InfoBar x:Name="CloseOnExitInfoBar"
x:Uid="CloseOnExitInfoBar"
x:Load="False"
IsClosable="True"
IsIconVisible="True"
IsOpen="False"
Severity="Informational">
<mux:InfoBar.ActionButton>
<Button x:Uid="InfoBarDismissButton"
Click="_CloseOnExitInfoDismissHandler" />
</mux:InfoBar.ActionButton>
</mux:InfoBar>
<mux:InfoBar x:Name="SetAsDefaultInfoBar"
x:Uid="SetAsDefaultInfoBar"
x:Load="False"
CloseButtonClick="_SetAsDefaultDismissHandler"
IsClosable="True"
IsIconVisible="True"
IsOpen="False"
Severity="Informational">
<mux:InfoBar.ActionButton>
<HyperlinkButton x:Uid="SetAsDefaultTip_OpenSettingsLink"
Click="_SetAsDefaultOpenSettingsHandler" />
</mux:InfoBar.ActionButton>
</mux:InfoBar>
</StackPanel>
<Grid x:Name="TabContent"
Grid.Row="1"
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
@ -110,39 +153,11 @@
</ContentDialog>
<local:CommandPalette x:Name="CommandPalette"
Grid.Row="1"
Grid.Row="2"
VerticalAlignment="Stretch"
PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" />
<StackPanel>
<mux:InfoBar x:Name="KeyboardServiceWarningInfoBar"
x:Load="False"
IsClosable="True"
IsIconVisible="True"
IsOpen="False"
Message="{x:Bind KeyboardServiceDisabledText, Mode=OneWay}"
Severity="Warning">
<mux:InfoBar.ActionButton>
<Button x:Uid="InfoBarDismissButton"
Click="_KeyboardServiceWarningInfoDismissHandler" />
</mux:InfoBar.ActionButton>
</mux:InfoBar>
<mux:InfoBar x:Name="CloseOnExitInfoBar"
x:Uid="CloseOnExitInfoBar"
x:Load="False"
IsClosable="True"
IsIconVisible="True"
IsOpen="False"
Severity="Informational">
<mux:InfoBar.ActionButton>
<Button x:Uid="InfoBarDismissButton"
Click="_CloseOnExitInfoDismissHandler" />
</mux:InfoBar.ActionButton>
</mux:InfoBar>
</StackPanel>
<!--
A TeachingTip with IsLightDismissEnabled="True" will immediately
dismiss itself if the window is unfocused (In Xaml Islands). This is

View file

@ -25,18 +25,6 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
TerminalTab::TerminalTab(const Profile& profile, const TermControl& control)
{
_rootPane = std::make_shared<Pane>(profile, control, true);
_rootPane->Id(_nextPaneId);
_activePane = _rootPane;
_mruPanes.insert(_mruPanes.begin(), _nextPaneId);
++_nextPaneId;
_Setup();
}
TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane)
{
_rootPane = rootPane;
@ -64,8 +52,9 @@ namespace winrt::TerminalApp::implementation
// focus the first one.
if (_activePane == nullptr)
{
_rootPane->FocusPane(firstId);
_activePane = _rootPane->GetActivePane();
const auto firstPane = _rootPane->FindPane(firstId);
firstPane->SetActive();
_activePane = firstPane;
}
// If the focused pane is a leaf, add it to the MRU panes
if (const auto id = _activePane->Id())
@ -503,39 +492,48 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Split the focused pane in our tree of panes, and place the
// given TermControl into the newly created pane.
// given pane into the tree of panes according to the split
// Arguments:
// - splitType: The type of split we want to create.
// - profile: The profile GUID to associate with the newly created pane.
// - control: A TermControl to use in the new pane.
// - splitType: The type of split we want to create
// - splitSize: The size of the split we want to create
// - pane: The new pane to add to the tree of panes; note that this pane
// could itself be a parent pane/the root node of a tree of panes
// Return Value:
// - <none>
void TerminalTab::SplitPane(SplitDirection splitType,
const float splitSize,
const Profile& profile,
TermControl& control)
std::shared_ptr<Pane> pane)
{
// Add the new event handlers to the new pane(s)
// and update their ids.
pane->WalkTree([&](auto p) {
_AttachEventHandlersToPane(p);
if (p->_IsLeaf())
{
p->Id(_nextPaneId);
_AttachEventHandlersToControl(p->Id().value(), p->_control);
_nextPaneId++;
}
return false;
});
// Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID
const auto activePaneId = _activePane->Id();
// Depending on which direction will be split, the new pane can be
// either the first or second child, but this will always return the
// original pane first.
auto [original, newPane] = _activePane->Split(splitType, splitSize, profile, control);
auto [original, newPane] = _activePane->Split(splitType, splitSize, pane);
// The active pane has an id if it is a leaf
if (activePaneId)
{
original->Id(activePaneId.value());
}
newPane->Id(_nextPaneId);
++_nextPaneId;
_activePane = original;
// Add a event handlers to the new panes' GotFocus event. When the pane
// gains focus, we'll mark it as the new active pane.
_AttachEventHandlersToControl(newPane->Id().value(), control);
_AttachEventHandlersToPane(original);
_AttachEventHandlersToPane(newPane);
// Immediately update our tracker of the focused pane now. If we're
// splitting panes during startup (from a commandline), then it's

View file

@ -21,7 +21,6 @@ namespace winrt::TerminalApp::implementation
struct TerminalTab : TerminalTabT<TerminalTab, TabBase>
{
public:
TerminalTab(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const winrt::Microsoft::Terminal::Control::TermControl& control);
TerminalTab(std::shared_ptr<Pane> rootPane);
// Called after construction to perform the necessary setup, which relies on weak_ptr
@ -40,8 +39,7 @@ namespace winrt::TerminalApp::implementation
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
winrt::Microsoft::Terminal::Control::TermControl& control);
std::shared_ptr<Pane> newPane);
void ToggleSplitOrientation();
winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);

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

@ -99,29 +99,57 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
// from the registered handler event function.
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
{
// Stash a local copy of _pfnHandoff before we stop listening.
auto localPfnHandoff = _pfnHandoff;
try
{
// Stash a local copy of _pfnHandoff before we stop listening.
auto localPfnHandoff = _pfnHandoff;
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
// COM does not automatically clean that up for us. We must do it.
s_StopListening();
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
// COM does not automatically clean that up for us. We must do it.
s_StopListening();
std::unique_lock lock{ _mtx };
std::unique_lock lock{ _mtx };
// Report an error if no one registered a handoff function before calling this.
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
// Report an error if no one registered a handoff function before calling this.
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
// Duplicate the handles from what we received.
// The contract with COM specifies that any HANDLEs we receive from the caller belong
// to the caller and will be freed when we leave the scope of this method.
// Making our own duplicate copy ensures they hang around in our lifetime.
RETURN_IF_FAILED(_duplicateHandle(in, in));
RETURN_IF_FAILED(_duplicateHandle(out, out));
RETURN_IF_FAILED(_duplicateHandle(signal, signal));
RETURN_IF_FAILED(_duplicateHandle(ref, ref));
RETURN_IF_FAILED(_duplicateHandle(server, server));
RETURN_IF_FAILED(_duplicateHandle(client, client));
// Duplicate the handles from what we received.
// The contract with COM specifies that any HANDLEs we receive from the caller belong
// to the caller and will be freed when we leave the scope of this method.
// Making our own duplicate copy ensures they hang around in our lifetime.
THROW_IF_FAILED(_duplicateHandle(in, in));
THROW_IF_FAILED(_duplicateHandle(out, out));
THROW_IF_FAILED(_duplicateHandle(signal, signal));
THROW_IF_FAILED(_duplicateHandle(ref, ref));
THROW_IF_FAILED(_duplicateHandle(server, server));
THROW_IF_FAILED(_duplicateHandle(client, client));
// Call registered handler from when we started listening.
return localPfnHandoff(in, out, signal, ref, server, client);
// Call registered handler from when we started listening.
THROW_IF_FAILED(localPfnHandoff(in, out, signal, ref, server, client));
#pragma warning(suppress : 26477)
TraceLoggingWrite(
g_hTerminalConnectionProvider,
"ReceiveTerminalHandoff_Success",
TraceLoggingDescription("successfully received a terminal handoff"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
return S_OK;
}
catch (...)
{
const auto hr = wil::ResultFromCaughtException();
#pragma warning(suppress : 26477)
TraceLoggingWrite(
g_hTerminalConnectionProvider,
"ReceiveTerminalHandoff_Failed",
TraceLoggingDescription("failed while receiving a terminal handoff"),
TraceLoggingHResult(hr),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
return hr;
}
}

View file

@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ConptyConnection.h"
#include <windows.h>
#include <userenv.h>
#include <UserEnv.h>
#include <winternl.h>
#include "ConptyConnection.g.cpp"
#include "CTerminalHandoff.h"
@ -276,24 +276,18 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const HANDLE hClientProcess) :
_initialRows{ 25 },
_initialCols{ 80 },
_commandline{ L"" },
_startingDirectory{ L"" },
_startingTitle{ L"" },
_environment{ nullptr },
_guid{},
_u8State{},
_u16Str{},
_buffer{},
_guid{ Utils::CreateGuid() },
_inPipe{ hIn },
_outPipe{ hOut }
{
THROW_IF_FAILED(ConptyPackPseudoConsole(hServerProcess, hRef, hSig, &_hPC));
if (_guid == guid{})
{
_guid = Utils::CreateGuid();
}
_piClient.hProcess = hClientProcess;
try
{
_commandline = _commandlineFromProcess(hClientProcess);
}
CATCH_LOG()
}
// Function Description:
@ -355,6 +349,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
return _guid;
}
winrt::hstring ConptyConnection::Commandline() const
{
return _commandline;
}
void ConptyConnection::Start()
try
{
@ -373,6 +372,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// window is expecting it to be on the first layout.
else
{
#pragma warning(suppress : 26477 26485 26494 26482 26446) // We don't control TraceLoggingWrite
TraceLoggingWrite(
g_hTerminalConnectionProvider,
"ConPtyConnectedToDefterm",
TraceLoggingDescription("Event emitted when ConPTY connection is started, for a defterm session"),
TraceLoggingGuid(_guid, "SessionGuid", "The WT_SESSION's GUID"),
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
}
@ -420,8 +429,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// EXIT POINT
const auto hr = wil::ResultFromCaughtException();
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") },
fmt::format(_errorFormat, hr),
fmt::format(_errorFormat, static_cast<unsigned int>(hr)),
_commandline) };
_TerminalOutputHandlers(failureText);
@ -448,6 +458,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
try
{
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) };
_TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(exitText);
@ -560,6 +571,38 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
CATCH_LOG()
// Returns the command line of the given process.
// Requires PROCESS_BASIC_INFORMATION | PROCESS_VM_READ privileges.
winrt::hstring ConptyConnection::_commandlineFromProcess(HANDLE process)
{
struct PROCESS_BASIC_INFORMATION
{
NTSTATUS ExitStatus;
PPEB PebBaseAddress;
ULONG_PTR AffinityMask;
KPRIORITY BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
} info;
THROW_IF_NTSTATUS_FAILED(NtQueryInformationProcess(process, ProcessBasicInformation, &info, sizeof(info), nullptr));
// PEB: Process Environment Block
// This is a funny structure allocated by the kernel which contains all sorts of useful
// information, only a tiny fraction of which are documented publicly unfortunately.
// Fortunately however it contains a copy of the command line the process launched with.
PEB peb;
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, info.PebBaseAddress, &peb, sizeof(peb), nullptr));
RTL_USER_PROCESS_PARAMETERS params;
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, peb.ProcessParameters, &params, sizeof(params), nullptr));
// Yeah I know... Don't use "impl" stuff... But why do you make something _that_ useful private? :(
// The hstring_builder allows us to create a hstring without intermediate copies. Neat!
winrt::impl::hstring_builder commandline{ params.CommandLine.Length / 2u };
THROW_IF_WIN32_BOOL_FALSE(ReadProcessMemory(process, params.CommandLine.Buffer, commandline.data(), params.CommandLine.Length, nullptr));
return commandline.to_hstring();
}
DWORD ConptyConnection::_OutputThread()
{
// Keep us alive until the output thread terminates; the destructor
@ -636,8 +679,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
HRESULT ConptyConnection::NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
try
{
auto conn = winrt::make<implementation::ConptyConnection>(signal, in, out, ref, server, client);
_newConnectionHandlers(conn);
_newConnectionHandlers(winrt::make<ConptyConnection>(signal, in, out, ref, server, client));
return S_OK;
}

View file

@ -38,6 +38,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void ClearBuffer();
winrt::guid Guid() const noexcept;
winrt::hstring Commandline() const;
static void StartInboundListener();
static void StopInboundListener();
@ -56,12 +57,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
private:
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
static winrt::hstring _commandlineFromProcess(HANDLE process);
HRESULT _LaunchAttachedClient() noexcept;
void _indicateExitWithStatus(unsigned int status) noexcept;
void _ClientTerminated() noexcept;
static HRESULT NewHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept;
uint32_t _initialRows{};
uint32_t _initialCols{};
hstring _commandline{};

View file

@ -5,10 +5,13 @@ import "ITerminalConnection.idl";
namespace Microsoft.Terminal.TerminalConnection
{
delegate void NewConnectionHandler(ConptyConnection connection);
[default_interface] runtimeclass ConptyConnection : ITerminalConnection
{
ConptyConnection();
Guid Guid { get; };
String Commandline { get; };
void ClearBuffer();
static event NewConnectionHandler NewConnection;

View file

@ -29,6 +29,4 @@ namespace Microsoft.Terminal.TerminalConnection
event Windows.Foundation.TypedEventHandler<ITerminalConnection, Object> StateChanged;
ConnectionState State { get; };
};
delegate void NewConnectionHandler(ITerminalConnection connection);
}

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());
@ -442,6 +453,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_settings.Opacity(newOpacity);
// GH#11285 - If the user is on Windows 10, and they changed the
// transparency of the control s.t. it should be partially opaque, then
// opt them in to acrylic. It's the only way to have transparency on
// Windows 10.
// We'll also turn the acrylic back off when they're fully opaque, which
// is what the Terminal did prior to 1.12.
if (!IsVintageOpacityAvailable())
{
_settings.UseAcrylic(newOpacity < 1.0);
}
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
_TransparencyChangedHandlers(*this, *eventArgs);
}
@ -570,6 +592,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_settings = settings;
// GH#11285 - If the user is on Windows 10, and they wanted opacity, but
// didn't explicitly request acrylic, then opt them in to acrylic.
// On Windows 11+, this isn't needed, because we can have vintage opacity.
if (!IsVintageOpacityAvailable() && _settings.Opacity() < 1.0 && !_settings.UseAcrylic())
{
_settings.UseAcrylic(true);
}
// Initialize our font information.
const auto fontFace = _settings.FontFace();
const short fontHeight = ::base::saturated_cast<short>(_settings.FontSize());
@ -581,6 +611,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all.
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, fontHeight }, CP_UTF8, false };
_actualFontFaceName = { fontFace };
_desiredFont = { _actualFont };
// Update the terminal core with its new Core settings
@ -596,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();
@ -630,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:
@ -723,6 +756,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto fontFace = _settings.FontFace();
const auto fontWeight = _settings.FontWeight();
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
_actualFontFaceName = { fontFace };
_desiredFont = { _actualFont };
auto lock = _terminal->LockForWriting();
@ -1001,7 +1035,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Size ControlCore::FontSize() const noexcept
{
const auto fontSize = GetFont().GetSize();
const auto fontSize = _actualFont.GetSize();
return {
::base::saturated_cast<float>(fontSize.X),
::base::saturated_cast<float>(fontSize.Y)
@ -1009,23 +1043,26 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
winrt::hstring ControlCore::FontFaceName() const noexcept
{
return winrt::hstring{ GetFont().GetFaceName() };
// This getter used to return _actualFont.GetFaceName(), however GetFaceName() returns a STL
// string and we need to return a WinRT string. This would require an additional allocation.
// This method is called 10/s by TSFInputControl at the time of writing.
return _actualFontFaceName;
}
uint16_t ControlCore::FontWeight() const noexcept
{
return static_cast<uint16_t>(GetFont().GetWeight());
return static_cast<uint16_t>(_actualFont.GetWeight());
}
til::size ControlCore::FontSizeInDips() const
{
const til::size fontSize{ GetFont().GetSize() };
const til::size fontSize{ _actualFont.GetSize() };
return fontSize.scale(til::math::rounding, 1.0f / ::base::saturated_cast<float>(_compositionScale));
}
TerminalConnection::ConnectionState ControlCore::ConnectionState() const
{
return _connection.State();
return _connection ? _connection.State() : TerminalConnection::ConnectionState::Closed;
}
hstring ControlCore::Title()
@ -1052,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:
@ -1272,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));
}
}
@ -1545,4 +1583,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return hstring(ss.str());
}
// Helper to check if we're on Windows 11 or not. This is used to check if
// we need to use acrylic to achieve transparency, because vintage opacity
// doesn't work in islands on win10.
// Remove when we can remove the rest of GH#11285
bool ControlCore::IsVintageOpacityAvailable() noexcept
{
OSVERSIONINFOEXW osver{};
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwBuildNumber = 22000;
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
}
}

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"
@ -149,6 +146,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
hstring ReadEntireBuffer() const;
static bool IsVintageOpacityAvailable() noexcept;
// -------------------------------- WinRT Events ---------------------------------
// clang-format off
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
@ -186,13 +185,14 @@ 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 };
FontInfoDesired _desiredFont;
FontInfo _actualFont;
winrt::hstring _actualFontFaceName;
// storage location for the leading surrogate of a utf-16 surrogate pair
std::optional<wchar_t> _leadingSurrogate{ std::nullopt };
@ -245,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

@ -43,6 +43,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_controlPadding = padding;
}
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
{
_parentProvider = parentProvider;
}
// Method Description:
// - Signals the ui automation client that the terminal's selection has
@ -110,30 +114,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// ScreenInfoUiaProvider doesn't actually use parameter, so just pass in nullptr
THROW_IF_FAILED(_uiaProvider->RangeFromChild(/* IRawElementProviderSimple */ nullptr,
&returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::RangeFromPoint(Windows::Foundation::Point screenLocation)
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->RangeFromPoint({ screenLocation.X, screenLocation.Y }, &returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::DocumentRange()
{
UIA::ITextRangeProvider* returnVal;
THROW_IF_FAILED(_uiaProvider->get_DocumentRange(&returnVal));
const auto parentProvider = this->ProviderFromPeer(*this);
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parentProvider);
return xutr.as<XamlAutomation::ITextRangeProvider>();
return _CreateXamlUiaTextRange(returnVal);
}
XamlAutomation::SupportedTextSelection InteractivityAutomationPeer::SupportedTextSelection()
@ -146,12 +141,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma endregion
#pragma region IControlAccessibilityInfo
COORD InteractivityAutomationPeer::GetFontSize() const
COORD InteractivityAutomationPeer::GetFontSize() const noexcept
{
return til::size{ til::math::rounding, _interactivity->Core().FontSize() };
}
RECT InteractivityAutomationPeer::GetBounds() const
RECT InteractivityAutomationPeer::GetBounds() const noexcept
{
return _controlBounds;
}
@ -164,12 +159,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return S_OK;
}
RECT InteractivityAutomationPeer::GetPadding() const
RECT InteractivityAutomationPeer::GetPadding() const noexcept
{
return _controlPadding;
}
double InteractivityAutomationPeer::GetScaleFactor() const
double InteractivityAutomationPeer::GetScaleFactor() const noexcept
{
return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
}
@ -180,6 +175,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
#pragma endregion
XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const
{
// LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this).
// Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer,
// using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator.
const auto parent{ _parentProvider.get() };
if (!parent)
{
return nullptr;
}
const auto xutr = winrt::make_self<XamlUiaTextRange>(returnVal, parent.ProviderFromPeer(parent));
return xutr.as<XamlAutomation::ITextRangeProvider>();
};
// Method Description:
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
// Arguments:
@ -194,11 +203,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::vector<XamlAutomation::ITextRangeProvider> vec;
vec.reserve(count);
auto parentProvider = this->ProviderFromPeer(*this);
for (int i = 0; i < count; i++)
{
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach()))
{
vec.emplace_back(std::move(xutr));
}
}
com_array<XamlAutomation::ITextRangeProvider> result{ vec };

View file

@ -43,6 +43,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SetControlBounds(const Windows::Foundation::Rect bounds);
void SetControlPadding(const Core::Padding padding);
void ParentProvider(Windows::UI::Xaml::Automation::Peers::AutomationPeer parentProvider);
#pragma region IUiaEventDispatcher
void SignalSelectionChanged() override;
@ -61,10 +62,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region IControlAccessibilityInfo Pattern
// Inherited via IControlAccessibilityInfo
virtual COORD GetFontSize() const override;
virtual RECT GetBounds() const override;
virtual RECT GetPadding() const override;
virtual double GetScaleFactor() const override;
virtual COORD GetFontSize() const noexcept override;
virtual RECT GetBounds() const noexcept override;
virtual RECT GetPadding() const noexcept override;
virtual double GetScaleFactor() const noexcept override;
virtual void ChangeViewport(SMALL_RECT NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion
@ -74,8 +75,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(CursorChanged, IInspectable, IInspectable);
private:
Windows::UI::Xaml::Automation::Provider::ITextRangeProvider _CreateXamlUiaTextRange(::ITextRangeProvider* returnVal) const;
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
weak_ref<Windows::UI::Xaml::Automation::Peers::AutomationPeer> _parentProvider;
til::rectangle _controlBounds{};
til::rectangle _controlPadding{};

View file

@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Control
{
[default_interface] runtimeclass InteractivityAutomationPeer :
@ -10,6 +9,7 @@ namespace Microsoft.Terminal.Control
void SetControlBounds(Windows.Foundation.Rect bounds);
void SetControlPadding(Microsoft.Terminal.Core.Padding padding);
void ParentProvider(Windows.UI.Xaml.Automation.Peers.AutomationPeer parentProvider);
event Windows.Foundation.TypedEventHandler<Object, Object> SelectionChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TextChanged;

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;
@ -297,37 +296,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
if (!newAppearance.BackgroundImage().empty())
{
Windows::Foundation::Uri imageUri{ newAppearance.BackgroundImage() };
// Check if the image brush is already pointing to the image
// in the modified settings; if it isn't (or isn't there),
// set a new image source for the brush
auto imageSource = BackgroundImage().Source().try_as<Media::Imaging::BitmapImage>();
if (imageSource == nullptr ||
imageSource.UriSource() == nullptr ||
imageSource.UriSource().RawUri() != imageUri.RawUri())
{
// Note that BitmapImage handles the image load asynchronously,
// which is especially important since the image
// may well be both large and somewhere out on the
// internet.
Media::Imaging::BitmapImage image(imageUri);
BackgroundImage().Source(image);
}
// Apply stretch, opacity and alignment settings
BackgroundImage().Stretch(newAppearance.BackgroundImageStretchMode());
BackgroundImage().Opacity(newAppearance.BackgroundImageOpacity());
BackgroundImage().HorizontalAlignment(newAppearance.BackgroundImageHorizontalAlignment());
BackgroundImage().VerticalAlignment(newAppearance.BackgroundImageVerticalAlignment());
}
else
{
BackgroundImage().Source(nullptr);
}
_SetBackgroundImage(newAppearance);
// Update our control settings
const auto bg = newAppearance.DefaultBackground();
@ -412,6 +381,57 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
// Method Description:
// - Sets background image and applies its settings (stretch, opacity and alignment)
// - Checks path validity
// Arguments:
// - newAppearance
// Return Value:
// - <none>
void TermControl::_SetBackgroundImage(const IControlAppearance& newAppearance)
{
if (newAppearance.BackgroundImage().empty())
{
BackgroundImage().Source(nullptr);
return;
}
Windows::Foundation::Uri imageUri{ nullptr };
try
{
imageUri = Windows::Foundation::Uri{ newAppearance.BackgroundImage() };
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
BackgroundImage().Source(nullptr);
return;
}
// Check if the image brush is already pointing to the image
// in the modified settings; if it isn't (or isn't there),
// set a new image source for the brush
auto imageSource = BackgroundImage().Source().try_as<Media::Imaging::BitmapImage>();
if (imageSource == nullptr ||
imageSource.UriSource() == nullptr ||
imageSource.UriSource().RawUri() != imageUri.RawUri())
{
// Note that BitmapImage handles the image load asynchronously,
// which is especially important since the image
// may well be both large and somewhere out on the
// internet.
Media::Imaging::BitmapImage image(imageUri);
BackgroundImage().Source(image);
}
// Apply stretch, opacity and alignment settings
BackgroundImage().Stretch(newAppearance.BackgroundImageStretchMode());
BackgroundImage().Opacity(newAppearance.BackgroundImageOpacity());
BackgroundImage().HorizontalAlignment(newAppearance.BackgroundImageHorizontalAlignment());
BackgroundImage().VerticalAlignment(newAppearance.BackgroundImageVerticalAlignment());
}
// Method Description:
// - Set up each layer's brush used to display the control's background.
// - Respects the settings for acrylic, background image and opacity from
@ -753,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);
}
@ -853,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.
@ -886,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
@ -968,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()))
@ -1807,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:
@ -1834,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
@ -1852,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)
@ -1881,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);
@ -1941,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);
}
}
@ -2042,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
@ -2250,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();
@ -2262,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();
@ -202,6 +196,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
void _ApplyUISettings(const IControlSettings&);
void _SetBackgroundImage(const IControlAppearance& newAppearance);
void _InitializeBackgroundBrush();
void _BackgroundColorChangedHandler(const IInspectable& sender, const IInspectable& args);
@ -250,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

@ -45,6 +45,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_contentAutomationPeer.SelectionChanged([this](auto&&, auto&&) { SignalSelectionChanged(); });
_contentAutomationPeer.TextChanged([this](auto&&, auto&&) { SignalTextChanged(); });
_contentAutomationPeer.CursorChanged([this](auto&&, auto&&) { SignalCursorChanged(); });
_contentAutomationPeer.ParentProvider(*this);
};
// Method Description:
@ -226,30 +227,4 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
#pragma endregion
// Method Description:
// - extracts the UiaTextRanges from the SAFEARRAY and converts them to Xaml ITextRangeProviders
// Arguments:
// - SAFEARRAY of UIA::UiaTextRange (ITextRangeProviders)
// Return Value:
// - com_array of Xaml Wrapped UiaTextRange (ITextRangeProviders)
com_array<XamlAutomation::ITextRangeProvider> TermControlAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges)
{
// transfer ownership of UiaTextRanges to this new vector
auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges);
int count = gsl::narrow<int>(providers.size());
std::vector<XamlAutomation::ITextRangeProvider> vec;
vec.reserve(count);
auto parentProvider = this->ProviderFromPeer(*this);
for (int i = 0; i < count; i++)
{
auto xutr = make_self<XamlUiaTextRange>(providers[i].detach(), parentProvider);
vec.emplace_back(xutr.as<XamlAutomation::ITextRangeProvider>());
}
com_array<XamlAutomation::ITextRangeProvider> result{ vec };
return result;
}
}

View file

@ -78,7 +78,5 @@ namespace winrt::Microsoft::Terminal::Control::implementation
private:
winrt::Microsoft::Terminal::Control::implementation::TermControl* _termControl;
Control::InteractivityAutomationPeer _contentAutomationPeer;
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
};
}

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

@ -6,6 +6,7 @@
#include "../types/TermControlUiaTextRange.hpp"
#include <UIAutomationClient.h>
#include <UIAutomationCoreApi.h>
#include "../types/UiaTracing.h"
// the same as COR_E_NOTSUPPORTED
// we don't want to import the CLR headers to get it
@ -182,6 +183,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
XamlAutomation::IRawElementProviderSimple XamlUiaTextRange::GetEnclosingElement()
{
::Microsoft::Console::Types::UiaTracing::TextRange::GetEnclosingElement(*static_cast<::Microsoft::Console::Types::UiaTextRangeBase*>(_uiaProvider.get()));
return _parentProvider;
}

View file

@ -0,0 +1,228 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// A lot of code was taken from
// https://github.com/Maximus5/ConEmu/blob/master/src/ConEmu/ColorFix.cpp
// and then adjusted to fit our style guidelines
#include "pch.h"
#include <Windows.h>
#include "ColorFix.hpp"
static constexpr double gMinThreshold = 12.0;
static constexpr double gExpThreshold = 20.0;
static constexpr double gLStep = 5.0;
static constexpr double rad006 = 0.104719755119659774;
static constexpr double rad025 = 0.436332312998582394;
static constexpr double rad030 = 0.523598775598298873;
static constexpr double rad060 = 1.047197551196597746;
static constexpr double rad063 = 1.099557428756427633;
static constexpr double rad180 = 3.141592653589793238;
static constexpr double rad275 = 4.799655442984406336;
static constexpr double rad360 = 6.283185307179586476;
ColorFix::ColorFix(COLORREF color)
{
rgb = color;
_ToLab();
}
// Method Description:
// - Helper function to calculate HPrime
double ColorFix::_GetHPrimeFn(double x, double y)
{
if (x == 0 && y == 0)
{
return 0;
}
const auto hueAngle = atan2(x, y);
return hueAngle >= 0 ? hueAngle : hueAngle + rad360;
}
// Method Description:
// - Given 2 colors, computes the DeltaE value between them
// Arguments:
// - x1: the first color
// - x2: the second color
// Return Value:
// - The DeltaE value between x1 and x2
double ColorFix::_GetDeltaE(ColorFix x1, ColorFix x2)
{
constexpr double kSubL = 1;
constexpr double kSubC = 1;
constexpr double kSubH = 1;
// Delta L Prime
const double deltaLPrime = x2.L - x1.L;
// L Bar
const double lBar = (x1.L + x2.L) / 2;
// C1 & C2
const double c1 = sqrt(pow(x1.A, 2) + pow(x1.B, 2));
const double c2 = sqrt(pow(x2.A, 2) + pow(x2.B, 2));
// C Bar
const double cBar = (c1 + c2) / 2;
// A Prime 1
const double aPrime1 = x1.A + (x1.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
// A Prime 2
const double aPrime2 = x2.A + (x2.A / 2) * (1 - sqrt(pow(cBar, 7) / (pow(cBar, 7) + pow(25.0, 7))));
// C Prime 1
const double cPrime1 = sqrt(pow(aPrime1, 2) + pow(x1.B, 2));
// C Prime 2
const double cPrime2 = sqrt(pow(aPrime2, 2) + pow(x2.B, 2));
// C Bar Prime
const double cBarPrime = (cPrime1 + cPrime2) / 2;
// Delta C Prime
const double deltaCPrime = cPrime2 - cPrime1;
// S sub L
const double sSubL = 1 + ((0.015 * pow(lBar - 50, 2)) / sqrt(20 + pow(lBar - 50, 2)));
// S sub C
const double sSubC = 1 + 0.045 * cBarPrime;
// h Prime 1
const double hPrime1 = _GetHPrimeFn(x1.B, aPrime1);
// h Prime 2
const double hPrime2 = _GetHPrimeFn(x2.B, aPrime2);
// Delta H Prime
const double deltaHPrime = 0 == c1 || 0 == c2 ? 0 : 2 * sqrt(cPrime1 * cPrime2) * sin(abs(hPrime1 - hPrime2) <= rad180 ? hPrime2 - hPrime1 : (hPrime2 <= hPrime1 ? hPrime2 - hPrime1 + rad360 : hPrime2 - hPrime1 - rad360) / 2);
// H Bar Prime
const double hBarPrime = (abs(hPrime1 - hPrime2) > rad180) ? (hPrime1 + hPrime2 + rad360) / 2 : (hPrime1 + hPrime2) / 2;
// T
const double t = 1 - 0.17 * cos(hBarPrime - rad030) + 0.24 * cos(2 * hBarPrime) + 0.32 * cos(3 * hBarPrime + rad006) - 0.20 * cos(4 * hBarPrime - rad063);
// S sub H
const double sSubH = 1 + 0.015 * cBarPrime * t;
// R sub T
const double rSubT = -2 * sqrt(pow(cBarPrime, 7) / (pow(cBarPrime, 7) + pow(25.0, 7))) * sin(rad060 * exp(-pow((hBarPrime - rad275) / rad025, 2)));
// Put it all together!
const double lightness = deltaLPrime / (kSubL * sSubL);
const double chroma = deltaCPrime / (kSubC * sSubC);
const double hue = deltaHPrime / (kSubH * sSubH);
return sqrt(pow(lightness, 2) + pow(chroma, 2) + pow(hue, 2) + rSubT * chroma * hue);
}
// Method Description:
// - Populates our L, A, B values, based on our r, g, b values
// - Converts a color in rgb format to a color in lab format
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void ColorFix::_ToLab()
{
double var_R = r / 255.0;
double var_G = g / 255.0;
double var_B = b / 255.0;
var_R = var_R > 0.04045 ? pow(((var_R + 0.055) / 1.055), 2.4) : var_R / 12.92;
var_G = var_G > 0.04045 ? pow(((var_G + 0.055) / 1.055), 2.4) : var_G / 12.92;
var_B = var_B > 0.04045 ? pow(((var_B + 0.055) / 1.055), 2.4) : var_B / 12.92;
var_R = var_R * 100.;
var_G = var_G * 100.;
var_B = var_B * 100.;
//Observer. = 2 degrees, Illuminant = D65
const double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
const double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
const double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
double var_X = X / 95.047; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
double var_Y = Y / 100.000; //ref_Y = 100.000
double var_Z = Z / 108.883; //ref_Z = 108.883
var_X = var_X > 0.008856 ? pow(var_X, (1. / 3.)) : (7.787 * var_X) + (16. / 116.);
var_Y = var_Y > 0.008856 ? pow(var_Y, (1. / 3.)) : (7.787 * var_Y) + (16. / 116.);
var_Z = var_Z > 0.008856 ? pow(var_Z, (1. / 3.)) : (7.787 * var_Z) + (16. / 116.);
L = (116. * var_Y) - 16.;
A = 500. * (var_X - var_Y);
B = 200. * (var_Y - var_Z);
}
// Method Description:
// - Populates our r, g, b values, based on our L, A, B values
// - Converts a color in lab format to a color in rgb format
// - Reference: http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void ColorFix::_ToRGB()
{
double var_Y = (L + 16.) / 116.;
double var_X = A / 500. + var_Y;
double var_Z = var_Y - B / 200.;
var_Y = (pow(var_Y, 3) > 0.008856) ? pow(var_Y, 3) : (var_Y - 16. / 116.) / 7.787;
var_X = (pow(var_X, 3) > 0.008856) ? pow(var_X, 3) : (var_X - 16. / 116.) / 7.787;
var_Z = (pow(var_Z, 3) > 0.008856) ? pow(var_Z, 3) : (var_Z - 16. / 116.) / 7.787;
double X = 95.047 * var_X; //ref_X = 95.047 (Observer= 2 degrees, Illuminant= D65)
double Y = 100.000 * var_Y; //ref_Y = 100.000
double Z = 108.883 * var_Z; //ref_Z = 108.883
var_X = X / 100.; //X from 0 to 95.047 (Observer = 2 degrees, Illuminant = D65)
var_Y = Y / 100.; //Y from 0 to 100.000
var_Z = Z / 100.; //Z from 0 to 108.883
double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;
double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;
var_R = var_R > 0.0031308 ? 1.055 * pow(var_R, (1 / 2.4)) - 0.055 : var_R = 12.92 * var_R;
var_G = var_G > 0.0031308 ? 1.055 * pow(var_G, (1 / 2.4)) - 0.055 : var_G = 12.92 * var_G;
var_B = var_B > 0.0031308 ? 1.055 * pow(var_B, (1 / 2.4)) - 0.055 : var_B = 12.92 * var_B;
r = (BYTE)std::clamp(var_R * 255., 0., 255.);
g = (BYTE)std::clamp(var_G * 255., 0., 255.);
b = (BYTE)std::clamp(var_B * 255., 0., 255.);
}
// Method Description:
// - Given foreground and background colors, change the foreground color to
// make it more perceivable if necessary
// - Arguments:
// - fg: the foreground color
// - bg: the background color
// - Return Value:
// - The foreground color after performing any necessary changes to make it more perceivable
COLORREF ColorFix::GetPerceivableColor(COLORREF fg, COLORREF bg)
{
ColorFix backLab(bg);
ColorFix frontLab(fg);
const double de1 = _GetDeltaE(frontLab, backLab);
if (de1 < gMinThreshold)
{
for (int i = 0; i <= 1; i++)
{
const double step = (i == 0) ? gLStep : -gLStep;
frontLab.L += step;
while (((i == 0) && (frontLab.L <= 100)) || ((i == 1) && (frontLab.L >= 0)))
{
const double de2 = _GetDeltaE(frontLab, backLab);
if (de2 >= gExpThreshold)
{
frontLab._ToRGB();
return frontLab.rgb;
}
frontLab.L += step;
}
}
}
return frontLab.rgb;
}

View file

@ -0,0 +1,49 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- ColorFix
Abstract:
- Implementation of perceptual color nudging, which allows the Terminal
to slightly shift the foreground color to make it more perceivable on
the current background (for cases where the foreground is very close
to being imperceivable on the background).
Author(s):
- Pankaj Bhojwani - Sep 2021
--*/
#pragma once
struct ColorFix
{
public:
ColorFix(COLORREF color);
static COLORREF GetPerceivableColor(COLORREF fg, COLORREF bg);
// RGB
union
{
struct
{
BYTE r, g, b, dummy;
};
COLORREF rgb;
};
// Lab
struct
{
double L, A, B;
};
private:
static double _GetHPrimeFn(double x, double y);
static double _GetDeltaE(ColorFix x1, ColorFix x2);
void _ToLab();
void _ToRGB();
};

View file

@ -67,5 +67,6 @@ namespace Microsoft.Terminal.Core
CursorStyle CursorShape;
UInt32 CursorHeight;
Boolean IntenseIsBright;
Boolean AdjustIndistinguishableColors;
};
}

View file

@ -3,6 +3,7 @@
#pragma once
#include "../../terminal/adapter/DispatchTypes.hpp"
#include "../../terminal/input/terminalInput.hpp"
#include "../../buffer/out/TextAttribute.hpp"
#include "../../types/inc/Viewport.hpp"
@ -39,24 +40,14 @@ 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;
virtual bool EnableWin32InputMode(const bool win32InputMode) noexcept = 0;
virtual bool SetCursorKeysMode(const bool applicationMode) noexcept = 0;
virtual bool SetKeypadMode(const bool applicationMode) noexcept = 0;
virtual bool SetScreenMode(const bool reverseMode) noexcept = 0;
virtual bool EnableVT200MouseMode(const bool enabled) noexcept = 0;
virtual bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept = 0;
virtual bool EnableSGRExtendedMouseMode(const bool enabled) noexcept = 0;
virtual bool EnableButtonEventMouseMode(const bool enabled) noexcept = 0;
virtual bool EnableAnyEventMouseMode(const bool enabled) noexcept = 0;
virtual bool EnableAlternateScrollMode(const bool enabled) noexcept = 0;
virtual bool EnableXtermBracketedPasteMode(const bool enabled) noexcept = 0;
virtual bool IsXtermBracketedPasteModeEnabled() const = 0;

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 },
@ -53,13 +51,22 @@ Terminal::Terminal() :
_taskbarState{ 0 },
_taskbarProgress{ 0 },
_trimBlockSelection{ false },
_intenseIsBright{ true }
_intenseIsBright{ true },
_adjustIndistinguishableColors{ true }
{
auto dispatch = std::make_unique<TerminalDispatch>(*this);
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
_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)
{
@ -72,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)
@ -171,15 +182,24 @@ 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();
for (int i = 0; i < 16; i++)
{
_colorTable.at(i) = til::color{ appearance.GetColorTableEntry(i) };
}
if (_adjustIndistinguishableColors)
{
_MakeAdjustedColorArray();
}
CursorType cursorShape = CursorType::VerticalBar;
switch (appearance.CursorShape())
@ -207,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;
@ -1204,9 +1222,7 @@ try
{
const gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
// First set up the basic 256 colors
Utils::Initialize256ColorTable(tableView);
// Then use fill the first 16 values with the Campbell scheme
Utils::InitializeCampbellColorTable(tableView);
Utils::InitializeColorTable(tableView);
// Then make sure all the values have an alpha of 255
Utils::SetColorTableAlpha(tableView, 0xff);
}

View file

@ -106,22 +106,13 @@ 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 EnableWin32InputMode(const bool win32InputMode) noexcept override;
bool SetCursorKeysMode(const bool applicationMode) noexcept override;
bool SetKeypadMode(const bool applicationMode) noexcept override;
bool SetInputMode(const ::Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) noexcept override;
bool SetScreenMode(const bool reverseMode) noexcept override;
bool EnableVT200MouseMode(const bool enabled) noexcept override;
bool EnableUTF8ExtendedMouseMode(const bool enabled) noexcept override;
bool EnableSGRExtendedMouseMode(const bool enabled) noexcept override;
bool EnableButtonEventMouseMode(const bool enabled) noexcept override;
bool EnableAnyEventMouseMode(const bool enabled) noexcept override;
bool EnableAlternateScrollMode(const bool enabled) noexcept override;
bool EnableXtermBracketedPasteMode(const bool enabled) noexcept override;
bool IsXtermBracketedPasteModeEnabled() const noexcept override;
@ -219,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;
@ -288,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;
@ -301,6 +289,7 @@ private:
bool _bracketedPasteMode;
bool _trimBlockSelection;
bool _intenseIsBright;
bool _adjustIndistinguishableColors;
size_t _taskbarState;
size_t _taskbarProgress;
@ -401,6 +390,9 @@ private:
Microsoft::Console::VirtualTerminal::SgrStack _sgrStack;
void _MakeAdjustedColorArray();
std::array<std::array<COLORREF, 18>, 18> _adjustedForegroundColors;
#ifdef UNIT_TESTING
friend class TerminalCoreUnitTests::TerminalBufferTests;
friend class TerminalCoreUnitTests::TerminalApiTest;

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,64 +455,14 @@ 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
bool Terminal::SetInputMode(const TerminalInput::Mode mode, const bool enabled) noexcept
try
{
_defaultFg = color;
// Repaint everything - the colors might have changed
_buffer->GetRenderTarget().TriggerRedrawAll();
_terminalInput->SetInputMode(mode, enabled);
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::EnableWin32InputMode(const bool win32InputMode) noexcept
{
_terminalInput->ChangeWin32InputMode(win32InputMode);
return true;
}
bool Terminal::SetCursorKeysMode(const bool applicationMode) noexcept
{
_terminalInput->ChangeCursorKeysMode(applicationMode);
return true;
}
bool Terminal::SetKeypadMode(const bool applicationMode) noexcept
{
_terminalInput->ChangeKeypadMode(applicationMode);
return true;
}
bool Terminal::SetScreenMode(const bool reverseMode) noexcept
try
{
@ -511,42 +474,6 @@ try
}
CATCH_RETURN_FALSE()
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
{
_terminalInput->EnableDefaultTracking(enabled);
return true;
}
bool Terminal::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
{
_terminalInput->SetUtf8ExtendedMode(enabled);
return true;
}
bool Terminal::EnableSGRExtendedMouseMode(const bool enabled) noexcept
{
_terminalInput->SetSGRExtendedMode(enabled);
return true;
}
bool Terminal::EnableButtonEventMouseMode(const bool enabled) noexcept
{
_terminalInput->EnableButtonEventTracking(enabled);
return true;
}
bool Terminal::EnableAnyEventMouseMode(const bool enabled) noexcept
{
_terminalInput->EnableAnyEventTracking(enabled);
return true;
}
bool Terminal::EnableAlternateScrollMode(const bool enabled) noexcept
{
_terminalInput->EnableAlternateScroll(enabled);
return true;
}
bool Terminal::EnableXtermBracketedPasteMode(const bool enabled) noexcept
{
_bracketedPasteMode = enabled;

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()
@ -321,9 +321,9 @@ CATCH_LOG_RETURN_FALSE()
// - applicationMode - set to true to enable Application Mode Input, false for Numeric Mode Input.
// Return Value:
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetKeypadMode(const bool fApplicationMode) noexcept
bool TerminalDispatch::SetKeypadMode(const bool applicationMode) noexcept
{
_terminalApi.SetKeypadMode(fApplicationMode);
_terminalApi.SetInputMode(TerminalInput::Mode::Keypad, applicationMode);
return true;
}
@ -334,7 +334,7 @@ bool TerminalDispatch::SetKeypadMode(const bool fApplicationMode) noexcept
// - True if handled successfully. False otherwise.
bool TerminalDispatch::SetCursorKeysMode(const bool applicationMode) noexcept
{
_terminalApi.SetCursorKeysMode(applicationMode);
_terminalApi.SetInputMode(TerminalInput::Mode::CursorKey, applicationMode);
return true;
}
@ -359,7 +359,7 @@ bool TerminalDispatch::SetScreenMode(const bool reverseMode) noexcept
// - True if handled successfully. False otherwise.
bool TerminalDispatch::EnableWin32InputMode(const bool win32Mode) noexcept
{
_terminalApi.EnableWin32InputMode(win32Mode);
_terminalApi.SetInputMode(TerminalInput::Mode::Win32, win32Mode);
return true;
}
@ -371,7 +371,7 @@ bool TerminalDispatch::EnableWin32InputMode(const bool win32Mode) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableVT200MouseMode(const bool enabled) noexcept
{
_terminalApi.EnableVT200MouseMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::DefaultMouseTracking, enabled);
return true;
}
@ -384,7 +384,7 @@ bool TerminalDispatch::EnableVT200MouseMode(const bool enabled) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
{
_terminalApi.EnableUTF8ExtendedMouseMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, enabled);
return true;
}
@ -397,7 +397,7 @@ bool TerminalDispatch::EnableUTF8ExtendedMouseMode(const bool enabled) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableSGRExtendedMouseMode(const bool enabled) noexcept
{
_terminalApi.EnableSGRExtendedMouseMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::SgrMouseEncoding, enabled);
return true;
}
@ -409,7 +409,7 @@ bool TerminalDispatch::EnableSGRExtendedMouseMode(const bool enabled) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) noexcept
{
_terminalApi.EnableButtonEventMouseMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, enabled);
return true;
}
@ -422,7 +422,7 @@ bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) noexcept
{
_terminalApi.EnableAnyEventMouseMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, enabled);
return true;
}
@ -435,7 +435,7 @@ bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) noexcept
// True if handled successfully. False otherwise.
bool TerminalDispatch::EnableAlternateScroll(const bool enabled) noexcept
{
_terminalApi.EnableAlternateScrollMode(enabled);
_terminalApi.SetInputMode(TerminalInput::Mode::AlternateScroll, enabled);
return true;
}

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