terminal/src/host/selection.hpp
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

185 lines
6.7 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- selection.hpp
Abstract:
- This module is used for managing the selection region
Author(s):
- Michael Niksa (MiNiksa) 4-Jun-2014
- Paul Campbell (PaulCam) 4-Jun-2014
Revision History:
- From components of clipbrd.h/.c and input.h/.c of v1 console.
--*/
#pragma once
#include "input.h"
#include "../interactivity/inc/IAccessibilityNotifier.hpp"
#include "../interactivity/inc/IConsoleWindow.hpp"
class Selection
{
public:
~Selection() = default;
std::vector<SMALL_RECT> GetSelectionRects() const;
void ShowSelection();
void HideSelection();
static Selection& Instance();
// Key selection generally refers to "mark mode" selection where
// the cursor is present and used to navigate 100% with the
// keyboard.
//
// Mouse selection means either the block or line mode selection
// usually initiated by the mouse.
//
// However, Mouse mode can also mean initiated with our
// shift+directional commands as no block cursor is required for
// navigation.
void InitializeMarkSelection();
void InitializeMouseSelection(const COORD coordBufferPos);
void SelectNewRegion(const COORD coordStart, const COORD coordEnd);
void SelectAll();
void ExtendSelection(_In_ COORD coordBufferPos);
void AdjustSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd);
void ClearSelection();
void ClearSelection(const bool fStartingNewSelection);
void ColorSelection(const SMALL_RECT& srRect, const TextAttribute attr);
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute attr);
// delete these or we can accidentally get copies of the singleton
Selection(Selection const&) = delete;
void operator=(Selection const&) = delete;
protected:
Selection();
private:
void _SetSelectionVisibility(const bool fMakeVisible);
void _PaintSelection() const;
void _CancelMarkSelection();
void _CancelMouseSelection();
// -------------------------------------------------------------------------------------------------------
// input handling (selectionInput.cpp)
public:
// key handling
// N.B.: This enumeration helps push up calling clipboard functions into
// the caller. This way, all of the selection code is independent of
// the clipboard and thus more easily shareable with Windows editions
// that do not have a clipboard (i.e. OneCore).
enum class KeySelectionEventResult
{
EventHandled,
EventNotHandled,
CopyToClipboard
};
KeySelectionEventResult HandleKeySelectionEvent(const INPUT_KEY_INFO* const pInputKeyInfo);
static bool s_IsValidKeyboardLineSelection(const INPUT_KEY_INFO* const pInputKeyInfo);
bool HandleKeyboardLineSelectionEvent(const INPUT_KEY_INFO* const pInputKeyInfo);
void CheckAndSetAlternateSelection();
// calculation functions
[[nodiscard]] static bool s_GetInputLineBoundaries(_Out_opt_ COORD* const pcoordInputStart, _Out_opt_ COORD* const pcoordInputEnd);
void GetValidAreaBoundaries(_Out_opt_ COORD* const pcoordValidStart, _Out_opt_ COORD* const pcoordValidEnd) const;
static bool s_IsWithinBoundaries(const COORD coordPosition, const COORD coordStart, const COORD coordEnd);
private:
// key handling
bool _HandleColorSelection(const INPUT_KEY_INFO* const pInputKeyInfo);
bool _HandleMarkModeSelectionNav(const INPUT_KEY_INFO* const pInputKeyInfo);
COORD WordByWordSelection(const bool fPrevious,
const Microsoft::Console::Types::Viewport& bufferSize,
const COORD coordAnchor,
const COORD coordSelPoint) const;
// -------------------------------------------------------------------------------------------------------
// selection state (selectionState.cpp)
public:
bool IsKeyboardMarkSelection() const;
bool IsMouseInitiatedSelection() const;
bool IsLineSelection() const;
bool IsInSelectingState() const;
bool IsInQuickEditMode() const;
bool IsAreaSelected() const;
bool IsMouseButtonDown() const;
DWORD GetPublicSelectionFlags() const noexcept;
COORD GetSelectionAnchor() const noexcept;
SMALL_RECT GetSelectionRectangle() const noexcept;
void SetLineSelection(const bool fLineSelectionOn);
bool ShouldAllowMouseDragSelection(const COORD mousePosition) const noexcept;
// TODO: these states likely belong somewhere else
void MouseDown();
void MouseUp();
private:
void _SaveCursorData(const Cursor& cursor) noexcept;
void _RestoreDataToCursor(Cursor& cursor) noexcept;
void _AlignAlternateSelection(const bool fAlignToLineSelect);
void _SetSelectingState(const bool fSelectingOn);
// TODO: extended edit key should probably be in here (remaining code is in cmdline.cpp)
// TODO: trim leading zeros should probably be in here (pending move of reactive code from input.cpp to selectionInput.cpp)
// TODO: enable color selection should be in here
// TODO: quick edit mode should be in here
// TODO: console selection mode should be in here
// TODO: consider putting word delims in here
// -- State/Flags --
// This replaces/deprecates CONSOLE_SELECTION_INVERTED on gci->SelectionFlags
bool _fSelectionVisible;
bool _fLineSelection; // whether to use line selection or block selection
bool _fUseAlternateSelection; // whether the user has triggered the alternate selection method
bool _allowMouseDragSelection; // true if the dragging the mouse should change the selection
// Flags for this DWORD are defined in wincon.h. Search for def:CONSOLE_SELECTION_IN_PROGRESS, etc.
DWORD _dwSelectionFlags;
// -- Current Selection Data --
// Anchor is the point the selection was started from (and will be one of the corners of the rectangle).
COORD _coordSelectionAnchor;
// Rectangle is the area inscribing the selection. It is extended to screen edges in a particular way for line selection.
SMALL_RECT _srSelectionRect;
// -- Saved Cursor Data --
// Saved when a selection is started for restoration later. Position is in character coordinates, not pixels.
COORD _coordSavedCursorPosition;
ULONG _ulSavedCursorSize;
bool _fSavedCursorVisible;
CursorType _savedCursorType;
#ifdef UNIT_TESTING
friend class SelectionTests;
friend class SelectionInputTests;
friend class ClipboardTests;
#endif
};