Repository: nvaccess/nvda

Issue:
Add support for Windows 11 Calculator
Hi,

A subtle follow-up to #9428:

### Background:
One of the side-effects of Windows as a Service, or for that matter, universal apps, is the changing nature of apps. One of the changes is renamed executables, the best known case being Windows 10/11 Mail (hxmail -> hxoutlook). Another change is UIA tree for apps where the old tree traversal route will not work due to rearranged UIA tree for apps, the best example being emoji panel.

### Is your feature request related to a problem? Please describe.
In #9428, NVDA introduced support for Windows 10 Calculator (calculator.exe), mostly to suppress UIA notification event announcement when entering expressions while speak typed characters is turned off. Windows 11 twists this in two ways:

* Calculator app executable was renamed to calculatorapp.exe
* UIA tree is different, so tree traversal to detect UIA notification announcement condition must be tweaked.

### Describe the solution you'd like
Add support for Windows 11 Calculator through a new app module. There are two implementation strategies:

1. Create a brand new Windows 11 Calculator app module that inherits from existing Windows 10 (modern) Calculator app module but tweaks UIA notification event handler's results tree traversal (in Windows 11 Calculator, one must move down one more level when fetching results element).
2. Tweak existing Windows 10 Calculator app module's UIA notification event handler to account for UIA tree differences, then add an alias app module for Windows 11 Calculator.

Both approaches are being tested via Windows App Essentials add-on (currently the first approach is available for users, with the second approach being tested in private and a proof of concept will be deployed to dev channel users within the next 24 hours). The upcoming pull request will "transplant" code from Windows App Essentials add-on to NVDA Core (people reading add-on source code should notice what that PR would look like).

### Describe alternatives you've considered
Leave it to add-ons to support Windows 11 Calculator.

### Additional context
App modules for modern Windows apps are subject to change based on latest happenings with apps themselves, especially since apps can be updated anytime (this is the main reason why I wait for a while before proposing an app module for a modern Windows app to be included in NVDA Core). Also, Calculator app is now open-source, so anyone can contribute to it (repo is hosted on GitHub), with newer releases focusing on Windows 11.

Thanks.


Discussion:

Resolving patch:
diff --git a/source/appModules/calculator.py b/source/appModules/calculator.py
--- a/source/appModules/calculator.py
+++ b/source/appModules/calculator.py
@@ -75,28 +75,28 @@ def event_nameChange(self, obj, nextHandler):
 		nextHandler()
 
 	def event_UIA_notification(self, obj, nextHandler, displayString=None, activityId=None, **kwargs):
-		# #12268: for "DisplayUpdated", announce display strings in braille and move on.
+		calculatorVersion = int(self.productVersion.split(".")[0])
+		# #12268: for "DisplayUpdated", announce display strings in braille  no matter what they are.
+		# There are other activity Id's such as "MemorySlotAdded" and "MemoryCleared"
+		# but they do not involve number entry.
+		# Therefore, only handle the below activity Id.
 		if activityId == "DisplayUpdated":
 			braille.handler.message(displayString)
-		try:
-			shouldAnnounceNotification = (
-				obj.previous.UIAAutomationId in
-				("numberPad", "UnitConverterRootGrid")
-			)
-		except AttributeError:
 			resultElement = api.getForegroundObject().children[1].lastChild
+			# Descend one more time in Windows 11 Calculator.
+			if calculatorVersion >= 11:
+				resultElement = resultElement.firstChild
 			# Redesigned in 2019 due to introduction of "always on top" i.e. compact overlay mode.
 			if resultElement.UIAElement.cachedClassName != "LandmarkTarget":
 				resultElement = resultElement.parent.children[1]
-			shouldAnnounceNotification = (
+			# Display string announcement is redundant if speak typed characters is on.
+			if (
 				resultElement
 				and resultElement.firstChild
-				and resultElement.firstChild.UIAAutomationId not in noCalculatorEntryAnnouncements
-			)
-		# Display updated activity ID seen when entering calculations should be ignored
-		# as as it is redundant if speak typed characters is on.
-		if shouldAnnounceNotification or activityId != "DisplayUpdated":
-			nextHandler()
+				and resultElement.firstChild.UIAAutomationId in noCalculatorEntryAnnouncements
+			):
+				return
+		nextHandler()
 
 	# A list of native commands to handle calculator result announcement.
 	_calculatorResultGestures = (
diff --git a/source/appModules/calculatorapp.py b/source/appModules/calculatorapp.py
new file mode 100644
--- /dev/null
+++ b/source/appModules/calculatorapp.py
@@ -0,0 +1,10 @@
+# A part of NonVisual Desktop Access (NVDA)
+# Copyright (C) 2022 NV Access Limited, Joseph Lee
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
+
+"""App module for Windows 11 Calculator"""
+
+# Renamed from Windows 10 Calculator in 2021 with the release of Windows 11.
+from .calculator import AppModule, noCalculatorEntryAnnouncements
+__all__ = ["AppModule", "noCalculatorEntryAnnouncements"]


Test patch: