Repository: nvaccess/nvda

Issue:
Windows 11 Notepad: status bar retrieval fails if Notepad UI is redesigned, specifically with tabbed Notepad
HI,

Covers current and upcoming Windows 11 Notepad changes:

### Overview
In ealry 2022, Microsoft released Notepad version 11 specifically designed for Windows 11, bringing with it modern Notepad interface and UIA-based text editor control. Almost a year later, on January 19, 2023, Microsoft released Notepad 11.2212 for Widnows Insiders subscribed to dev channel. The most notable change with 11.2212 is tabbed Notepad - that is, multiple files can be opened under one window. This also brings revised UIA tree for Notepad window, specifically the position of the status bar in the UIA tree changes as tabs are opened and closed, causing current status bar retrieval to fail.

### Steps to reproduce:
Prerequisite: Windows 11 Insider Preview build 25281 or later with Notepad 11.2212 and later. For comparison, use current Notepad (11.2210) running on latest stable Windows 11 build (22621 will do):

1. Open Notepad.
2. Type something.
3. Obtain status bar text (NVDA+End in desktop layout, NVDA+Shift+End in laptop layout).
4. In Notepad 11.2212 and later, open a new Notepad tab (for now you must click new tab button).
5. Retrieve status bar text.

### Actual behavior:
In Notepad 11.2212, NVDA does not announce status bar text.

### Expected behavior:
NVDA announces status bar text.

### NVDA logs, crash dumps and other attachments:

### System configuration
#### NVDA installed/portable/running from source:
Installed

#### NVDA version:
alpha-27590,180c9f2b

#### Windows version:
Windows 11 22H2 beta (build 22623)/dev (25281)

#### Name and version of other software in use when reproducing the issue:
Notepad 11.2210 (stable)/11.2212 (dev)

#### Other information about your system:
Build 25281 is a virtual machine

### 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.
Reproducible in NVDA 2022.4

#### If NVDA add-ons are disabled, is your problem still occurring?
Yes

#### Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?
Yes

### Solution
Thankfully status bar is the second to last item in Notepad UIA tree, and this formula also holds true in 11.2212. This can change depending on the progress of tabbed Notepad in coming weeks, but for compatibility, the new position should be used.

Thanks.


Discussion:

Resolving patch:
diff --git a/source/appModules/notepad.py b/source/appModules/notepad.py
--- a/source/appModules/notepad.py
+++ b/source/appModules/notepad.py
@@ -1,5 +1,5 @@
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2022 NV Access Limited, Joseph Lee
+# Copyright (C) 2022-2023 NV Access Limited, Joseph Lee
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -7,13 +7,17 @@
 While this app module also covers older Notepad releases,
 this module provides workarounds for Windows 11 Notepad."""
 
+from comtypes import COMError
 import appModuleHandler
 import api
+import UIAHandler
+from NVDAObjects.UIA import UIA
+from NVDAObjects import NVDAObject
 
 
 class AppModule(appModuleHandler.AppModule):
 
-	def _get_statusBar(self):
+	def _get_statusBar(self) -> NVDAObject:
 		"""Retrieves Windows 11 Notepad status bar.
 		In Windows 10 and earlier, status bar can be obtained by looking at the bottom of the screen.
 		Windows 11 Notepad uses Windows 11 UI design (top-level window is labeled "DesktopWindowXamlSource",
@@ -32,11 +36,16 @@ def _get_statusBar(self):
 		# Thankfully, of all the UIA objects encountered, document window has a unique window class name.
 		if api.getFocusObject().windowClassName != "RichEditD2DPT":
 			raise NotImplementedError()
-		# Look for a specific child as some children report the same UIA properties such as class name.
-		# Make sure to look for a foreground UIA element which hosts status bar content if visible.
-		notepadStatusBarIndex = 7
-		statusBar = api.getForegroundObject().children[notepadStatusBarIndex].firstChild
-		# No location for a disabled status bar i.e. location is 0 (x, y, width, height).
-		if not any(statusBar.location):
-			raise NotImplementedError()
+		# Obtain status bar text across Notepad 11 releases.
+		clientObject = UIAHandler.handler.clientObject
+		condition = clientObject.createPropertyCondition(UIAHandler.UIA_AutomationIdPropertyId, "ContentTextBlock")
+		walker = clientObject.createTreeWalker(condition)
+		notepadWindow = clientObject.elementFromHandle(api.getForegroundObject().windowHandle)
+		try:
+			element = walker.getFirstChildElement(notepadWindow)
+			# Is status bar even showing?
+			element = element.buildUpdatedCache(UIAHandler.handler.baseCacheRequest)
+		except (ValueError, COMError):
+			raise NotImplementedError
+		statusBar = UIA(UIAElement=element).parent
 		return statusBar


Test patch: