terminal/src/cascadia/TerminalCore/Terminal.hpp

231 lines
10 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include <conattrs.hpp>
#include "../../buffer/out/textBuffer.hpp"
#include "../../renderer/inc/IRenderData.hpp"
#include "../../terminal/parser/StateMachine.hpp"
#include "../../terminal/input/terminalInput.hpp"
#include "../../types/inc/Viewport.hpp"
#include "../../cascadia/terminalcore/ITerminalApi.hpp"
#include "../../cascadia/terminalcore/ITerminalInput.hpp"
// You have to forward decl the ICoreSettings here, instead of including the header.
// If you include the header, there will be compilation errors with other
// headers that include Terminal.hpp
namespace winrt::Microsoft::Terminal::Settings
{
struct ICoreSettings;
}
namespace Microsoft::Terminal::Core
{
class Terminal;
}
class Microsoft::Terminal::Core::Terminal final :
public Microsoft::Terminal::Core::ITerminalApi,
public Microsoft::Terminal::Core::ITerminalInput,
public Microsoft::Console::Render::IRenderData
{
public:
Terminal();
virtual ~Terminal(){};
void Create(COORD viewportSize,
SHORT scrollbackLines,
Microsoft::Console::Render::IRenderTarget& renderTarget);
void CreateFromSettings(winrt::Microsoft::Terminal::Settings::ICoreSettings settings,
Microsoft::Console::Render::IRenderTarget& renderTarget);
void UpdateSettings(winrt::Microsoft::Terminal::Settings::ICoreSettings settings);
// Write goes through the parser
void Write(std::wstring_view stringView);
[[nodiscard]] std::shared_lock<std::shared_mutex> LockForReading();
[[nodiscard]] std::unique_lock<std::shared_mutex> LockForWriting();
short GetBufferHeight() const noexcept;
#pragma region ITerminalApi
// These methods are defined in TerminalApi.cpp
bool PrintString(std::wstring_view stringView) override;
bool ExecuteChar(wchar_t wch) override;
bool SetTextToDefaults(bool foreground, bool background) override;
bool SetTextForegroundIndex(BYTE colorIndex) override;
bool SetTextBackgroundIndex(BYTE colorIndex) override;
bool SetTextRgbColor(COLORREF color, bool foreground) override;
bool BoldText(bool boldOn) override;
bool UnderlineText(bool underlineOn) override;
bool ReverseText(bool reversed) override;
bool SetCursorPosition(short x, short y) override;
COORD GetCursorPosition() override;
bool DeleteCharacter(const unsigned int uiCount) override;
bool InsertCharacter(const unsigned int uiCount) override;
bool EraseCharacters(const unsigned int numChars) override;
bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override;
bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override;
bool SetWindowTitle(std::wstring_view title) override;
bool SetColorTableEntry(const size_t tableIndex, const COLORREF dwColor) override;
bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) override;
bool SetDefaultForeground(const COLORREF dwColor) override;
bool SetDefaultBackground(const COLORREF dwColor) override;
#pragma endregion
#pragma region ITerminalInput
// These methods are defined in Terminal.cpp
bool SendKeyEvent(const WORD vkey, const Microsoft::Terminal::Core::ControlKeyStates states) override;
[[nodiscard]] HRESULT UserResize(const COORD viewportSize) noexcept override;
void UserScrollViewport(const int viewTop) override;
int GetScrollOffset() override;
#pragma endregion
#pragma region IRenderData
// These methods are defined in TerminalRenderData.cpp
Microsoft::Console::Types::Viewport GetViewport() noexcept override;
const TextBuffer& GetTextBuffer() noexcept override;
const FontInfo& GetFontInfo() noexcept override;
const TextAttribute GetDefaultBrushColors() noexcept override;
const COLORREF GetForegroundColor(const TextAttribute& attr) const noexcept override;
const COLORREF GetBackgroundColor(const TextAttribute& attr) const noexcept override;
COORD GetCursorPosition() const noexcept override;
bool IsCursorVisible() const noexcept override;
bool IsCursorOn() const noexcept override;
ULONG GetCursorHeight() const noexcept override;
ULONG GetCursorPixelWidth() const noexcept override;
CursorType GetCursorStyle() const noexcept override;
COLORREF GetCursorColor() const noexcept override;
bool IsCursorDoubleWidth() const noexcept override;
const std::vector<Microsoft::Console::Render::RenderOverlay> GetOverlays() const noexcept override;
const bool IsGridLineDrawingAllowed() noexcept override;
std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept override;
Accessibility: Set-up UIA Tree (#1691) **The Basics of Accessibility** - [What is a User Interaction Automation (UIA) Tree?](https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-tree-overview) - Other projects (i.e.: Narrator) can take advantage of this UIA tree and are used to present information within it. - Some things like XAML already have a UIA Tree. So some UIA tree navigation and features are already there. It's just a matter of getting them hooked up and looking right. **Accessibility in our Project** There's a few important classes... regarding Accessibility... - **WindowUiaProvider**: This sets up the UIA tree for a window. So this is the top-level for the UIA tree. - **ScreenInfoUiaProvider**: This sets up the UIA tree for a terminal buffer. - **UiaTextRange**: This is essential to interacting with the UIA tree for the terminal buffer. Actually gets portions of the buffer and presents them. regarding the Windows Terminal window... - **BaseWindow**: The foundation to a window. Deals with HWNDs and that kind of stuff. - **IslandWindow**: This extends `BaseWindow` and is actually what holds our Windows Terminal - **NonClientIslandWindow**: An extension of the `IslandWindow` regarding ConHost... - **IConsoleWindow**: This is an interface for the console window. - **Window**: This is the actual window for ConHost. Extends `IConsoleWindow` - `IConsoleWindow` changes: - move into `Microsoft::Console::Types` (a shared space) - Have `IslandWindow` extend it - `WindowUiaProvider` changes: - move into `Microsoft::Console::Types` (a shared space) - Hook up `WindowUiaProvider` to IslandWindow (yay! we now have a tree) ### Changes to the WindowUiaProvider As mentioned earlier, the WindowUiaProvider is the top-level UIA provider for our projects. To reuse as much code as possible, I created `Microsoft::Console::Types::WindowUiaProviderBase`. Any existing functions that reference a `ScreenInfoUiaProvider` were virtual-ized. In each project, a `WindowUiaProvider : WindowUiaProviderBase` was created to define those virtual functions. Note that that will be the main difference between ConHost and Windows Terminal moving forward: how many TextBuffers are on the screen. So, ConHost should be the same as before, with only one `ScreenInfoUiaProvider`, whereas Windows Terminal needs to (1) update which one is on the screen and (2) may have multiple on the screen. 🚨 Windows Terminal doesn't have the `ScreenInfoUiaProvider` hooked up yet. We'll have all the XAML elements in the UIA tree. But, since `TermControl` is a custom XAML Control, I need to hook up the `ScreenInfoUiaProvider` to it. This work will be done in a new PR and resolve GitHub Issue #1352. ### Moved to `Microsoft::Console::Types` These files got moved to a shared area so that they can be used by both ConHost and Windows Terminal. This means that any references to the `ServiceLocator` had to be removed. - `IConsoleWindow` - Windows Terminal: `IslandWindow : IConsoleWindow` - `ScreenInfoUiaProvider` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - `UiaTextRange` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - since most of the functions were `static`, that means that an `IRenderData` had to be added into most of them. ### Changes to IRenderData Since `IRenderData` is now being used to abstract out `ServiceLocator` and `SCREEN_INFORMATION`, I had to add a few functions here: - `bool IsAreaSelected()` - `void ClearSelection()` - `void SelectNewRegion(...)` - `HRESULT SearchForText(...)` `SearchForText()` is a problem here. The overall new design is great! But Windows Terminal doesn't have a way to search for text in the buffer yet, whereas ConHost does. So I'm punting on this issue for now. It looks nasty, but just look at all the other pretty things here. :)
2019-07-30 00:21:15 +02:00
bool IsAreaSelected() const override;
void ClearSelection() override;
void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override;
// TODO GitHub #605: Search functionality
// For now, just adding it here to make UiaTextRange easier to create (Accessibility)
// We should actually abstract this out better once Windows Terminal has Search
HRESULT SearchForText(_In_ BSTR text,
_In_ BOOL searchBackward,
_In_ BOOL ignoreCase,
_Outptr_result_maybenull_ ITextRangeProvider** ppRetVal,
unsigned int _start,
unsigned int _end,
std::function<unsigned int(IRenderData*, const COORD)> _coordToEndpoint,
std::function<COORD(IRenderData*, const unsigned int)> _endpointToCoord,
std::function<IFACEMETHODIMP(ITextRangeProvider**)> Clone) override;
const std::wstring GetConsoleTitle() const noexcept override;
void LockConsole() noexcept override;
void UnlockConsole() noexcept override;
#pragma endregion
void SetWriteInputCallback(std::function<void(std::wstring&)> pfn) noexcept;
void SetTitleChangedCallback(std::function<void(const std::wstring_view&)> pfn) noexcept;
void SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept;
void SetBackgroundCallback(std::function<void(const uint32_t)> pfn) noexcept;
void SetCursorVisible(const bool isVisible) noexcept;
bool IsCursorBlinkingAllowed() const noexcept;
#pragma region TextSelection
2019-06-19 00:53:29 +02:00
// These methods are defined in TerminalSelection.cpp
const bool IsSelectionActive() const noexcept;
void DoubleClickSelection(const COORD position);
void TripleClickSelection(const COORD position);
void SetSelectionAnchor(const COORD position);
void SetEndSelectionPosition(const COORD position);
void SetBoxSelection(const bool isEnabled) noexcept;
const std::wstring RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace) const;
#pragma endregion
private:
std::function<void(std::wstring&)> _pfnWriteInput;
std::function<void(const std::wstring_view&)> _pfnTitleChanged;
std::function<void(const int, const int, const int)> _pfnScrollPositionChanged;
std::function<void(const uint32_t)> _pfnBackgroundColorChanged;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::TerminalInput> _terminalInput;
std::wstring _title;
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;
COLORREF _defaultFg;
COLORREF _defaultBg;
bool _snapOnInput;
#pragma region Text Selection
enum SelectionExpansionMode
{
Cell,
Word,
Line
};
COORD _selectionAnchor;
COORD _endSelectionPosition;
bool _boxSelection;
bool _selectionActive;
SHORT _selectionAnchor_YOffset;
SHORT _endSelectionPosition_YOffset;
std::wstring _wordDelimiters;
SelectionExpansionMode _multiClickSelectionMode;
#pragma endregion
std::shared_mutex _readWriteLock;
// TODO: These members are not shared by an alt-buffer. They should be
// encapsulated, such that a Terminal can have both a main and alt buffer.
std::unique_ptr<TextBuffer> _buffer;
Microsoft::Console::Types::Viewport _mutableViewport;
SHORT _scrollbackLines;
// _scrollOffset is the number of lines above the viewport that are currently visible
// If _scrollOffset is 0, then the visible region of the buffer is the viewport.
int _scrollOffset;
// TODO this might not be the value we want to store.
// We might want to store the height in the scrollback that's currenty visible.
// Think on this some more.
// For example: While looking at the scrollback, we probably want the visible region to "stick"
// to the region they scrolled to. If that were the case, then every time we move _mutableViewport,
// we'd also need to update _offset.
// However, if we just stored it as a _visibleTop, then that point would remain fixed -
// Though if _visibleTop == _mutableViewport.Top, then we'd need to make sure to update
// _visibleTop as well.
// Additionally, maybe some people want to scroll into the history, then have that scroll out from
// underneath them, while others would prefer to anchor it in place.
// Either way, we sohould make this behavior controlled by a setting.
int _ViewStartIndex() const noexcept;
int _VisibleStartIndex() const noexcept;
Microsoft::Console::Types::Viewport _GetMutableViewport() const noexcept;
Microsoft::Console::Types::Viewport _GetVisibleViewport() const noexcept;
void _InitializeColorTable();
void _WriteBuffer(const std::wstring_view& stringView);
void _NotifyScrollEvent();
2019-06-19 00:53:29 +02:00
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
std::vector<SMALL_RECT> _GetSelectionRects() const;
const SHORT _ExpandWideGlyphSelectionLeft(const SHORT xPos, const SHORT yPos) const;
const SHORT _ExpandWideGlyphSelectionRight(const SHORT xPos, const SHORT yPos) const;
COORD _ExpandDoubleClickSelectionLeft(const COORD position) const;
COORD _ExpandDoubleClickSelectionRight(const COORD position) const;
const bool _isWordDelimiter(std::wstring_view cellChar) const;
const COORD _ConvertToBufferCell(const COORD viewportPos) const;
2019-06-19 00:53:29 +02:00
#pragma endregion
};