Expose Text Attributes to UI Automation#10336
Conversation
| // TODO CARLOS: how do I get the font size in points? | ||
| if (queryFontSize == 0) //_pData->GetFontInfo().GetUnscaledSize()) | ||
| { | ||
| Clone(ppRetVal); | ||
| } |
There was a problem hiding this comment.
You mean instead of pixels? I believe in the dx renderer is a conversion. You could move it to a helper
There was a problem hiding this comment.
I'm gonna punt on this one and file it as a follow-up because...
- we don't expect the font size to change within the buffer, so exposing it isn't urgent
- I'll have to do a different approach between ConHost and Windows Terminal here. And that just sounds like extra work for an already bulky PR.
7807ba6 to
2ae0ab8
Compare
Known Issues
Things that I should do
|
|
Please also consider regression testing against legacy console (i.e. disable the UIA feature flag and check text formatting). |
| // - limit - boundaries for the iterator to operate within | ||
| // - until - X,Y position in buffer for last position for the iterator to read (inclusive) |
There was a problem hiding this comment.
what is the difference between a limit and an until? Why can they be different?
There was a problem hiding this comment.
Updated the comment to be more clear. Also renamed...
limit-->boundsuntil-->limit
Theoretically, you could have...
bounds = bufferSize&limit = (3,3): iterate fromatthroughlimit(explores (4,3) --> (5,3) --> (6,3))bounds = (5,5)&limit = (3,3): iterate fromatthroughlimitacrossbounds(explores (4,3) --> (5,3) --> (0,4))
| THROW_IF_FAILED(_uiaProvider->GetAttributeValue(textAttributeId, &result)); | ||
|
|
||
| // Convert the resulting VARIANT into a format that is consumable by XAML. | ||
| switch (result.vt) |
There was a problem hiding this comment.
I'm surprised that nobody has made a C++ visitor specialization for a variant
| case UIA_IsReadOnlyAttributeId: | ||
| { | ||
| pRetVal->vt = VT_BOOL; | ||
| pRetVal->boolVal = VARIANT_FALSE; |
There was a problem hiding this comment.
well this rather depends: the entire buffer is technically "read-only"... it just happens to change when the connected application receives input.
A non-read-only buffer suggests that you could, e.g., select a region and delete it... or change its formatting or something.
There was a problem hiding this comment.
The Text Attribute ID docs:
Identifies the IsReadOnly text attribute, which indicates whether the text is read-only (TRUE) or can be modified (FALSE).
@codeofdusk made an interesting suggestion as to the interpretation of that text: append "by the user" at the end. In console, a user can interact with the buffer via key strokes, and those key strokes may modify any section of the buffer. Surprisingly, something like "text on a webpage" is also not read only! IsReadOnly seems to be limited to text that is disabled and cannot be interacted with in any way.
2ae0ab8 to
2ee0cd8
Compare
2ee0cd8 to
a99fa3c
Compare
lhecker
left a comment
There was a problem hiding this comment.
I'm convinced that you should the COORD limit logic into the 2 places that need it instead of TextBufferCellIterator.
TextBufferCellIterator at this point is already something of a magic hambeast that does everything and I actually think that concerns are better separated, by not having this logic in the basic iterator. Creating an iterator-adapter for instance would be rather clean, but just doing the loop-early-exit logic in those 2 places is also clean.
| size_t _hyperlinkPatternId; | ||
|
|
||
| std::wstring _workingDirectory; | ||
| std::optional<FontInfo> _fontInfo; |
There was a problem hiding this comment.
you may just want to drop the optional and initialize this _fontInfo directly with the fake fontinfo value in TerminalRenderData.cpp:R48.
There was a problem hiding this comment.
Then stomp it when the font changes.
There was a problem hiding this comment.
qq: why does this go through a value stored on the TerminalCore (which is a cache that could get out of sync) and not through some other component that knows what the font is?
There was a problem hiding this comment.
like: TSFInputControl had the same problem -- had to get the font -- and I am concerned that now there are two ways to get the font (new one and old one)
There was a problem hiding this comment.
So this is the part that sucks. IUiaData is down in TerminalCore. But all of the font info (_desiredFont and _actualFont) is actually up in ControlCore. Because of this, we need to have ControlCore tell TerminalCore "hey, the font change to X" here.
TSFInputControl looks like it works directly with the TerminalControl (now ControlCore since the split) to get what it needs.
|
@carlos-zamora @DHowett Since it might be interesting for others as well I'm going to post it here: C++ requires short-circuit evaluation and thus compilers will absolutely refuse to eagerly evaluate or inline the left-hand side of a boolean operator. For instance if you write You can see the drastic difference here: https://godbolt.org/z/sd9qY8Meh However |
it appears that you have talked yourself around into wanting short-circuit evaluation after all ;) |
Derp. Sorry, I missed that.
You mean function pointer like C-style? Or is there a nicer way to encapsulate it? |
…lambda for attr verification
|
Checked in with Leonard offline. I made it so that we don't return the lambda. Instead, we basically "run the lambda" that we would've returned. |
|
@DHowett putting this on your radar @zadjii-msft idk if you wanted to take another look, but I'll leave you as assigned anyways haha. |
DHowett
left a comment
There was a problem hiding this comment.
I trust both other signers here, and I did a medium-close read of the code myself. Best way to know is to try it.
|
Hello @carlos-zamora! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
|
🎉 Handy links: |
Fix-up of #10964. Summary of the issue: The link to Expose Text Attributes to UI Automation microsoft/terminal#10336 was broken by t2t preproc directives. Additional clarification on "NVDA API levels" might be appreciated by some users.
Summary of the Pull Request
This implements
GetAttributeValueandFindAttributeforUiaTextRangeBase(the sharedITextRangeProviderfor Conhost and Windows Terminal). This also updatesUiaTracingto collect more useful information on these function calls.References
#7000 - Epic
Text Attribute Identifiers
ITextRangeProvider::GetAttributeValue
ITextRangeProvider::FindAttribute
PR Checklist
Detailed Description of the Pull Request / Additional comments
TextBuffer:TextBufferCellIteratorthat takes in an end position. This simplifies the logic drastically as we can now use this iterator to navigate through the text buffer. The iterator can also expose the position in the buffer.UiaTextRangeBase:TextAttributes in the text buffer. To extract them, we generate an attribute verification function via_getAttrVerificationFn(), then use that to verify if a given cell has the desired attribute.GetAttributeValue: Retrieve the attribute verification of the first cell in the range. Then, verify that the entire range has that attribute by iterating through the text range. If a cell does not have that attribute, return the "reserved mixed attribute value".FindAttribute: Iterate through the text range and leverage the attribute verification function to find the first contiguous range with that attribute. Then, make the end exclusive and output aUiaTextRangeBase. This function must be able to perform a search backwards, so we abstract the "start" and "end" intoresultFirstAnchorandresultSecondAnchor, then perform post processing to output a validUiaTextRangeBase.UiaTracing:GetAttributeValue: Log uia text range, desired attribute, resulting attribute metadata, and the type of the result.FindAttribute: Log uia text range, desired attribute and attribute metadata, if we were searching backwards, the type of the result, and the resulting text range.AttributeTypeis a nice way to understand/record if the result was either of the reserved UIA values, a normal result, or an error.UiaTextRangeTests:GetAttributeValue:_getAttrVerificationFn())FindAttribute:IsItalic. NOTE: I'm explicitly only testing one of the standard text attributes because the logic is largely the same between all of them and they leverage_getAttrVerificationFn().Validation Steps Performed