terminal/src/host/selection.hpp
Carlos Zamora 96496d8154
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-29 15:21:15 -07:00

197 lines
7.3 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 "..\types\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;
static SMALL_RECT s_BisectSelection(const short sStringLength,
const COORD coordTargetPoint,
const SCREEN_INFORMATION& screenInfo,
const SMALL_RECT rect);
static std::vector<SMALL_RECT> s_GetSelectionRects(const SMALL_RECT& selectionRect,
const COORD selectionAnchor,
const bool lineSelection);
void _CancelMarkSelection();
void _CancelMouseSelection();
static std::unique_ptr<Selection> _instance;
// -------------------------------------------------------------------------------------------------------
// 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;
COLORREF _savedCursorColor;
CursorType _savedCursorType;
#ifdef UNIT_TESTING
friend class SelectionTests;
friend class SelectionInputTests;
friend class ClipboardTests;
#endif
};