Repository: nvaccess/nvda

Issue:
UIA in Console: unable to access terminal after scrolling of long text

### Steps to reproduce:
1. Ensure that "Use UI Automation to access the Windows Console when available" is enabled.
2. Open cmd or powershell.
3. Execute the follow line to generate some random text (you can use many other solutions for that like read a huge file using 'cat'):
   `wsl head -c 5000000 /dev/urandom|tr -dc "\u20-\u80"|fold -w80`
4. Wait until the previous command is finished (i.e. until the prompt is back).
5. Move in another window/go to desktop.
6. Return to cmd.

### Actual behavior:
We can't access to the Terminal content. No problem if UIA in Window Consoles is disabled.

### Expected behavior:
We should explore the Terminal.

### System configuration
#### NVDA installed/portable/running from source:
Installed

#### NVDA version:
alpha-21145,ac31a795

#### Windows version:
Windows 10 Insider (64-bit) build 20231.1000

#### Name and version of other software in use when reproducing the issue:
cmd, powershell
#### Other information about your system:

### Other questions
#### Does the issue still occur after restarting your computer?
Yes

#### Have you tried any other versions of NVDA? If so, please report their behaviors.
No

#### If addons are disabled, is your problem still occuring?
Yes

#### Did you try to run the COM registry fixing tool in NVDA menu / tools?
No


Discussion:

Resolving patch:
diff --git a/source/NVDAObjects/UIA/winConsoleUIA.py b/source/NVDAObjects/UIA/winConsoleUIA.py
--- a/source/NVDAObjects/UIA/winConsoleUIA.py
+++ b/source/NVDAObjects/UIA/winConsoleUIA.py
@@ -48,10 +48,8 @@ def _getBoundingRange(self, obj, position):
 		if position == textInfos.POSITION_FIRST:
 			collapseToEnd = False
 		elif position == textInfos.POSITION_LAST:
-			# We must pull back the end by one character otherwise when we collapse to end,
-			# a console bug results in a textRange covering the entire console buffer!
-			# Strangely the *very* last character is a special blank point
-			# so we never seem to miss a real character.
+			# The exclusive end hangs off the end of the visible ranges.
+			# Move back one character to remain within bounds.
 			_rangeObj.MoveEndpointByUnit(
 				UIAHandler.TextPatternRangeEndpoint_End,
 				UIAHandler.NVDAUnitsToUIAUnits['character'],
@@ -366,6 +364,11 @@ def _get_TextInfo(self):
 		return consoleUIATextInfo if self.is21H1Plus else consoleUIATextInfoPre21H1
 
 	def _getTextLines(self):
+		if self.is21H1Plus:
+			# #11760: the 21H1 UIA console wraps across lines.
+			# When text wraps, NVDA starts reading from the beginning of the visible text for every new line of output.
+			# Use the superclass _getTextLines instead.
+			return super()._getTextLines()
 		# This override of _getTextLines takes advantage of the fact that
 		# the console text contains linefeeds for every line
 		# Thus a simple string splitlines is much faster than splitting by unit line.
@@ -373,6 +376,7 @@ def _getTextLines(self):
 		text = ti.text or ""
 		return text.splitlines()
 
+
 	def detectPossibleSelectionChange(self):
 		try:
 			return super().detectPossibleSelectionChange()


Test patch: