[PR #3659] [MERGED] Enable Word Navigation in UiaTextRange #25458

Open
opened 2026-01-31 09:09:39 +00:00 by claunia · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/microsoft/terminal/pull/3659
Author: @carlos-zamora
Created: 11/21/2019
Status: Merged
Merged: 12/12/2019
Merged by: @carlos-zamora

Base: masterHead: dev/cazamor/acc/word-nav


📝 Commits (10+)

  • 7a310c8 Switch to WRL::ComPtr for ScreenInfoUiaProvider and UiaTextRange
  • b331937 Upgrade WindowUiaProvider
  • 1aa2b0d Make CreateUTR functions return HRESULT and use outptr
  • f60246b Cleaner creation process with proper RETURN_IF_FAILED() and returning S_OK
  • 87f6c5c Code formatter
  • 81543c4 fix merge conflicts
  • 9d57e06 fix static analysis errors
  • b33dd6d Add warning suppression for dumb computer thing
  • 0077a46 Applied feedback.
  • f9ad0a1 fix merge conflicts

📊 Changes

17 files changed (+1310 additions, -158 deletions)

View changed files

📝 src/buffer/out/textBuffer.cpp (+112 -0)
📝 src/buffer/out/textBuffer.hpp (+11 -0)
📝 src/cascadia/TerminalControl/TermControlUiaProvider.cpp (+10 -7)
📝 src/cascadia/TerminalControl/TermControlUiaProvider.hpp (+5 -2)
📝 src/cascadia/TerminalControl/UiaTextRange.cpp (+13 -9)
📝 src/cascadia/TerminalControl/UiaTextRange.hpp (+9 -4)
📝 src/cascadia/TerminalCore/Terminal.hpp (+0 -7)
📝 src/cascadia/TerminalCore/TerminalSelection.cpp (+4 -71)
📝 src/interactivity/win32/screenInfoUiaProvider.cpp (+10 -7)
📝 src/interactivity/win32/screenInfoUiaProvider.hpp (+5 -2)
📝 src/interactivity/win32/uiaTextRange.cpp (+13 -9)
📝 src/interactivity/win32/uiaTextRange.hpp (+9 -4)
📝 src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp (+466 -0)
📝 src/types/ScreenInfoUiaProviderBase.cpp (+10 -5)
📝 src/types/ScreenInfoUiaProviderBase.h (+8 -3)
📝 src/types/UiaTextRangeBase.cpp (+568 -25)
📝 src/types/UiaTextRangeBase.hpp (+57 -3)

📄 Description

Summary of the Pull Request

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.

PR Checklist

Detailed Description of the Pull Request / Additional comments

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)

Reusing our old code

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.

Validation Steps Performed

I'll be adding more tests for the kind of things that I was doing. If you really want to test it, I recommend you use Accessibility Insights. Click on the Terminal Control. On the bottom right, click on "Text Pattern Explore...". Then just mess around with any options that say "word" on it.

Concerns/Discussion Points

  1. How does this model expand to non-english languages? How is word navigation expected to work on CJK characters? As of now, we keep going until we hit a boundary or whitespace. Is that functionally correct?
  2. A lot of this code is repeated, unfortunately. It's repeated just enough where I want to do a refactor. HOWEVER, the same issues exist in the other code in this doc (I particularly noticed it in MoveByCharacter(). I think it might be better to do all the refactoring in one big sweep, but I'm open to discussion on this.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/microsoft/terminal/pull/3659 **Author:** [@carlos-zamora](https://github.com/carlos-zamora) **Created:** 11/21/2019 **Status:** ✅ Merged **Merged:** 12/12/2019 **Merged by:** [@carlos-zamora](https://github.com/carlos-zamora) **Base:** `master` ← **Head:** `dev/cazamor/acc/word-nav` --- ### 📝 Commits (10+) - [`7a310c8`](https://github.com/microsoft/terminal/commit/7a310c8096f6638d7b32bee7b5e016e7706229e5) Switch to WRL::ComPtr for ScreenInfoUiaProvider and UiaTextRange - [`b331937`](https://github.com/microsoft/terminal/commit/b3319373f4ebe0e28057fcb059be53202f8d8b0f) Upgrade WindowUiaProvider - [`1aa2b0d`](https://github.com/microsoft/terminal/commit/1aa2b0d3f0501e7f67b17e6016bfae4d4f4bbf44) Make CreateUTR functions return HRESULT and use outptr - [`f60246b`](https://github.com/microsoft/terminal/commit/f60246b26f88e0a62085001aa8392b302d328117) Cleaner creation process with proper RETURN_IF_FAILED() and returning S_OK - [`87f6c5c`](https://github.com/microsoft/terminal/commit/87f6c5cf279f5cc0e5f36536e63f8c7e1359aac6) Code formatter - [`81543c4`](https://github.com/microsoft/terminal/commit/81543c44ee52481f907878d304174bb38eb79f1b) fix merge conflicts - [`9d57e06`](https://github.com/microsoft/terminal/commit/9d57e062795a4dbb9464a73aad6773f996b3ca81) fix static analysis errors - [`b33dd6d`](https://github.com/microsoft/terminal/commit/b33dd6d8acb055fa8afd725e8480638c8a21272e) Add warning suppression for dumb computer thing - [`0077a46`](https://github.com/microsoft/terminal/commit/0077a46d7b9b87af526efdc17474ecef4b4a95fd) Applied feedback. - [`f9ad0a1`](https://github.com/microsoft/terminal/commit/f9ad0a1c7418228d088bff5de46a002531aa192d) fix merge conflicts ### 📊 Changes **17 files changed** (+1310 additions, -158 deletions) <details> <summary>View changed files</summary> 📝 `src/buffer/out/textBuffer.cpp` (+112 -0) 📝 `src/buffer/out/textBuffer.hpp` (+11 -0) 📝 `src/cascadia/TerminalControl/TermControlUiaProvider.cpp` (+10 -7) 📝 `src/cascadia/TerminalControl/TermControlUiaProvider.hpp` (+5 -2) 📝 `src/cascadia/TerminalControl/UiaTextRange.cpp` (+13 -9) 📝 `src/cascadia/TerminalControl/UiaTextRange.hpp` (+9 -4) 📝 `src/cascadia/TerminalCore/Terminal.hpp` (+0 -7) 📝 `src/cascadia/TerminalCore/TerminalSelection.cpp` (+4 -71) 📝 `src/interactivity/win32/screenInfoUiaProvider.cpp` (+10 -7) 📝 `src/interactivity/win32/screenInfoUiaProvider.hpp` (+5 -2) 📝 `src/interactivity/win32/uiaTextRange.cpp` (+13 -9) 📝 `src/interactivity/win32/uiaTextRange.hpp` (+9 -4) 📝 `src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp` (+466 -0) 📝 `src/types/ScreenInfoUiaProviderBase.cpp` (+10 -5) 📝 `src/types/ScreenInfoUiaProviderBase.h` (+8 -3) 📝 `src/types/UiaTextRangeBase.cpp` (+568 -25) 📝 `src/types/UiaTextRangeBase.hpp` (+57 -3) </details> ### 📄 Description ## Summary of the Pull Request 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. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3161 * [x] CLA signed. * [x] Tests added/passed * [x] General Word Navigation * [x] Empty Buffer Navigation * [x] Requires documentation to be updated (I think not!) ## Detailed Description of the Pull Request / Additional comments ### 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](https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-uiautomationtextunits)) - 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) ### Reusing our old code #### 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. ## Validation Steps Performed I'll be adding more tests for the kind of things that I was doing. If you really want to test it, I recommend you use [Accessibility Insights](https://accessibilityinsights.io/). Click on the Terminal Control. On the bottom right, click on "Text Pattern Explore...". Then just mess around with any options that say "word" on it. ## Concerns/Discussion Points 1. How does this model expand to non-english languages? How is word navigation expected to work on CJK characters? As of now, we keep going until we hit a boundary or whitespace. Is that functionally correct? 2. A lot of this code is repeated, unfortunately. It's repeated _just enough_ where I want to do a refactor. HOWEVER, the same issues exist in the other code in this doc (I particularly noticed it in `MoveByCharacter()`. I think it might be better to do all the refactoring in one big sweep, but I'm open to discussion on this. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
claunia added the pull-request label 2026-01-31 09:09:39 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#25458