Commit graph

25 commits

Author SHA1 Message Date
msftbot[bot] 267deaaf70
Improve Word Navigation/Selection Performance (#4797)
## Summary of the Pull Request
1) Improves the performance of word-recognition operations such as word
   navigation in UIA and selection.

2) Fixes a bug where attempting to find the next word in UIA, when none
   exists, would hang

3) TraceLogging code only runs when somebody is listening

## Detailed Description of the Pull Request / Additional comments
- The concept of a delimiter class got moved to the CharRow.
- The buffer iterator used to save a lot more information than we needed
- I missed updating a tracing function after making GetSelection return
  one text range. That is fixed now.


## Validation Steps Performed
Performed Word Navigation under Narrator and NVDA.
NOTE: The release build should be used when testing to optimize
performance

Closes #4703
2020-03-04 23:10:10 +00:00
Carlos Zamora 360c655acc
UIA: Fix GetVisibleRanges() and add Tracing (#4495)
## Summary of the Pull Request
Debugging our custom UIA providers has been a painful experience because outputting content to VS may result in UIA Clients getting impatient and giving up on extracting data.

Adding tracing allows us to debug these providers without getting in the way of reproducing a bug. This will help immensely with developing accessibility features on Windows Terminal and Console.

This pull request additionally contains payload from #4526:
* Make GetVisibleRanges() return one range (and add tracing for it).
`ScreenInfoUiaProvider::GetVisibleRanges()` used to return one range per line of visible text. The documentation for this function says that we should return one per contiguous span of text. Since all of the text in the TermControl will always be contiguous (at least by our standards), we should only ever be returning one range.

## PR Checklist
* [x] Closes #1914. Closes #4507.
* [x] CLA signed

## Detailed Description of the Pull Request / Additional comments
`UiaTracing` is a singleton class that is in charge of registration for trace logging. `TextRange` is used to trace `UiaTextRange`, whereas `TextProvider` is used to trace `ScreenInfoUiaProviderBase`.

`_getValue()` is overloaded to transform complex objects and enums into a string for logging.

`_getTextValue()` had to be added to be able to trace the text a UiaTextRange included. This makes following UiaTextRanges much simpler.

## Validation Steps Performed
Performed a few operations when under NVDA/Narrator and manually checked the results.
2020-02-20 23:50:43 +00:00
Carlos Zamora d0c8221c6e
Make ScreenInfoUiaProvider::GetSelection() Return One Selection (#4466)
## Summary of the Pull Request
We used to return multiple text ranges to represent one selection. We only support one selection at a time, so we should only return one range.

Additionally, I moved all TriggerSelection() calls to the renderer from Terminal to TermControl for consistency. This ensures we only call it _once_ when we make a change to our selection state.

## References
#2447 - helps polish Signaling for Selection
#4465 - This is more apparent as the problem holding back Signaling for Selection

## PR Checklist
* [x] Closes #4452 

Tested using Accessibility Insights.
2020-02-20 23:03:50 +00:00
Carlos Zamora 681a0dbd57
Limit Concept of TextBuffer's Size in UIA (#4523)
## Summary of the Pull Request
In UIA Providers, update the concept of the size of the text buffer to just go down to the virtual bottom. This significantly increases performance to the point that it can even be used in the Debug build.

## PR Checklist
* [x] Closes #4485 
* [x] CLA signed.

## Detailed Description of the Pull Request / Additional comments
We already actually have this concept exposed to us via the IUiaData. So we're just leveraging that and putting it in a helper function `_getBufferSize()`.

## Validation Steps Performed
Tested word nav on Narrator (previously hung). Now it works on the Debug build. Previously, using the release build was necessary to be able to test this feature.
2020-02-10 23:23:19 +00:00
Carlos Zamora d375461a66
Adjust GetBoundingRect for Inclusive end (#4449)
GetBoundingRect() has inclusive endpoints. I previously assumed end was exclusive so I drew the bounding rect wrong.

This also means that we should allow start and end to be the same. Which means that FailFastIf would get hit...
2020-02-03 13:25:08 -08:00
Carlos Zamora 55b638801b
Introduce UiaTextRangeBase::FindText() for Accessibility (#4373)
Moved `FindText` to `UiaTextRangeBase`. Now that Search is a shared component (thanks #3279), I can just reuse it basically as-is.

#3279 - Make Search a shared component
#4018 - UiaTextRange Refactor

I removed it from the two different kinds of UiaTextRange and put it in the base class.

I needed a very minor change to ensure we convert from an inclusive end (from Search) to an exclusive end (in UTR).

Worked with `FindText` was globally messed with in windows.h. So we had to do a few weird things there (thanks Michael).

No need for additional tests because it _literally_ just sets up a Searcher and calls it.
2020-01-31 23:26:19 +00:00
Carlos Zamora 29df540174
Refactor UiaTextRange For Improved Navigation and Reliability (#4018)
## Summary of the Pull Request
This pull request is intended to achieve the following goals...
1) reduce duplicate code
2) remove static functions
3) improve readability
4) improve reliability
5) improve code-coverage for testing
6) establish functioning text buffer navigation in Narrator and NVDA

This also required a change to the wrapper class `XamlUiaTextRange` that has been causing issues with Narrator and NVDA.

See below for additional context.

## References
#3976 - I believe this might have been a result of improperly handling degenerate ranges. Fixed here.
#3895 - reduced the duplicate code. No need to separate into different files
#2160 - same as #3976 above
#1993 - I think just about everything is no longer static

## PR Checklist
* [x] Closes #3895, Closes #1993, Closes #3976, Closes #2160 
* [x] CLA signed
* [x] Tests added/passed

## Detailed Description of the Pull Request / Additional comments

### UiaTextRange
- converted endpoints into the COORD system in the TextBuffer coordinate space
- `start` is inclusive, `end` is exclusive. A degenerate range is when start == end.
- all functions are no longer static
- `MoveByUnit()` functions now rely on `MoveEndpointByUnit()` functions
- removed unnecessary typedefs like `Endpoint`, `ScreenInfoRow`, etc..
- relied more heavily on existing functionality from `TextBuffer` and `Viewport`

### XamlUiaTextRange
- `GetAttributeValue()` must return a special HRESULT that signifies that the requested attribute is not supported. This was the cause of a number of inconsistencies between Narrator and NVDA.
- `FindText()` should return `nullptr` if nothing was found. #4373 properly fixes this functionality now that Search is a shared module

### TextBuffer
- Word navigation functionality is entirely in `TextBuffer` for proper abstraction
- a total of 6 functions are now dedicated to word navigation to get a good understanding of the differences between a "word" in Accessibility and a "word" in selection

As an example, consider a buffer with this text in it:
"  word   other  "
In selection, a "word" is defined as the range between two delimiters, so the words in the example include ["  ", "word", "   ", "other", "  "].
In accessibility , a "word" includes the delimiters after a range of readable characters, so the words in the example include ["word   ", "other  "].

Additionally, accessibility word navigation must be able to detect if it is on the first or last word. This resulted in a slight variant of word navigation functions that return a boolean instead of a COORD.

Ideally, these functions can be consolidated, but that is too risky for a PR of this size as it can have an effect on selection.

### Viewport
- the concept of `EndExclusive` is added. This is used by UiaTextRange's `end` anchor as it is exclusive. To signify that the last character in the buffer is included in this buffer, `end` must be one past the end of the buffer. This is `EndExclusive`
- Since many functions check if the given `COORD` is in bounds, a flag must be set to allow `EndExclusive` as a valid `COORD` that is in bounds.

### Testing
- word navigation testing relies more heavily on TextBuffer tests
- additional testing was created for non-movement focused functions of UiaTextRange
- The results have been compared to Microsoft Word and some have been verified by UiAutomation/Narrator contacts as expected results.

## Validation Steps Performed
Tests pass
Narrator works
NVDA works
2020-01-31 20:59:39 +00:00
Carlos Zamora 4b48f74f5f
Enable Word Navigation in UiaTextRange (#3659)
Enables support for word navigation when using an automation client (i.e.: Narrator, etc...). Specifically, adds this functionality to the UiaTextRange class. The only delimiter used is whitespace because that's how words are separated in English.

# General "Word Movement" Expectations
The resulting text range should include any word break characters that are present at the end of the word, but before the start of the next word. (Source)

If you already are on a word, getting the "next word" means you skip the word you are on, and highlight the upcoming word appropriately. (similar idea when moving backwards)


# Word Expansion
Since word selection is supposed to detect word delimiters already, I figured I'd reuse that code. I moved it from TerminalCore to the TextBuffer.

Then I built on top of it by adding an optional additional parameter that decides if you want to include...
- the delimiter run when moving forward
- the character run when moving backwards
It defaults to false so that we don't have to care when using it in selection. But we change it to true when using it in our UiaTextRange

# UiaTextRange
The code is based on character movement. This allows us to actually work with boundary conditions.

The main thing to remember here is that each text range is recorded as a MoveState. The text range is most easily defined when you think about the start Endpoint and the end Endpoint. An Endpoint is just a linear 1-dimensional indexing of the text buffer. Examples:
- Endpoint 0 --> (0,0)
- Endpoint 79 --> (79,0) (when the buffer width is 80)
- Endpoint 80 -->(0,1) (when the buffer width is 80)
- When moving forward, the strategy is to focus on moving the end Endpoint. That way, we properly get the indexing for the "next" word (this also fixes a wrapping issue). Then, we update the start Endpoint. (This is reversed for moving backwards).
- When moving a specific Endpoint, we just have a few extra if statements to properly adjust for moving start vs end.

# Hooking it up
All we really had to do is add an enum. This part was super easy :)

I originally wanted the delimiters to be able to be defined. I'm not so sure about that anymore. Either way, I hardcoded our delimiter into a variable so if we ever want to expand on it or make that customizable, we just modify that variable.

# Defining your own word delimiters

- Import a word delimiter into the constructor of the ScreenInfoUiaProvider (SIUP)
  - This defines a word delimiter for all the UiaTextRanges (UTR) created by in this context
- import a word delimiter into the UTR directly
  - this provides more control over what a "word" is
  - this can be useful if you have an idea of what text a particular UTR will encounter and you want to customize the word navigation for it (i.e consider adding / or \\ for file paths)

The default param of " " is scattered throughout because this is the word delimiter used in the English language.
2019-12-12 15:22:12 -08:00
Carlos Zamora 2915be5b51
Upgrade UiaProviders to WRL::ComPtr (#3051) 2019-11-21 16:08:37 -08:00
Dustin L. Howett (MSFT) 4991b9f1b2 Switch all of the UIA providers to WRL::RuntimeClass (#3213)
* Switch all of the UIA providers to WRL::RuntimeClass
Fixes #3209.
References #3051.

Co-authored-by: Carlos Zamora <cazamor@microsoft.com>
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
2019-10-17 15:32:30 -07:00
Michael Niksa 7d9534bfa8 constexprs have to go into the headers or other usages can't find them. Imagine that. 2019-09-04 10:59:18 -07:00
Michael Niksa 6735311fc9 Suppress last two errors (C26455 default constructor throw in DxEngine because it's due for refactoring soon anyway & C26444 custom construction/destruction on OutputCellIterator because I can't see what's going on and it needs more investigation and shouldn't hold this up). Also run codeformat. 2019-09-03 16:18:19 -07:00
Michael Niksa 594dca993b C26429, mark gsl::not_null on places where we don't test for null (shouldn't need to, internal methods only. 2019-09-03 11:18:28 -07:00
Michael Niksa c956913a28 C26497, use constexpr for functions that could be evaluated at compile time. 2019-09-03 10:30:06 -07:00
Michael Niksa bbdfdf91eb C26462, const local variables that are unchanged. 2019-09-03 10:04:30 -07:00
Michael Niksa d5d7cf420d C26494, uninitalized local variables 2019-09-03 10:02:18 -07:00
Michael Niksa cdfbf8f106 C26474, don't use static_cast when an implicit cast is acceptable. 2019-09-03 08:53:54 -07:00
Michael Niksa 30e8e7f3a3 C26429, symbols not tested for nullness. 2019-09-03 08:46:24 -07:00
Michael Niksa 4f1157c044 C26447,C26440 - is noexcept but can throw or doesn't throw but not noexcept 2019-08-29 15:23:07 -07:00
Michael Niksa 8579d8905a C26451, promote before arithmetic if storing in larger result size (or use safe math) 2019-08-29 13:41:51 -07:00
Michael Niksa 8ea7401dc9 C26472, no static_cast for arithmetic conversions. narrow or narrow_cast 2019-08-29 13:19:01 -07:00
Michael Niksa b33a59816e C26496, mark const if it's never written after creation 2019-08-29 11:27:39 -07:00
Michael Niksa 65dec36cb1 C26446, Use .at instead of array indices 2019-08-29 11:05:32 -07:00
Carlos Zamora be52880620 Accessibility: Add BoundingRects to UiaTextRanges (#2423) 2019-08-20 17:50:34 -07:00
Carlos Zamora 667c0286c1
Accessibility: Refactor Providers (#2414)
Refactors the accessibility providers (ScreenInfoUiaProvider and UiaTextRange) into a better separated model between ConHost and Windows Terminal.

ScreenInfoUiaProviderBase and UiaTextRangeBase are introduced. ConHost and Windows Terminal implement their own versions of ScreenInfoUiaProvider and UiaTextRange that inherit from their respective base classes.

WindowsTerminal's ScreenInfoUiaProvider --> TermControlUiaProvider
2019-08-20 16:32:44 -07:00
Renamed from src/types/UiaTextRange.cpp (Browse further)