33# This file is covered by the GNU General Public License.
44# See the file COPYING for more details.
55
6- """App module for Windows 10 Calculator"""
6+ """App module for Windows 10 Calculator.
7+ This is also the base app module for Windows 11 Calculator."""
78
89import appModuleHandler
910import api
@@ -39,6 +40,8 @@ class AppModule(appModuleHandler.AppModule):
3940 _shouldAnnounceResult = False
4041 # Name change says the same thing multiple times for some items.
4142 _resultsCache = ""
43+ # #13383: for some commands (such as number row keys), NVDA should not announce calculator results.
44+ _noCalculatorResultsGesturePressed = False
4245
4346 def event_NVDAObject_init (self , obj ):
4447 if not isinstance (obj , UIA ):
@@ -75,6 +78,12 @@ def event_nameChange(self, obj, nextHandler):
7578 nextHandler ()
7679
7780 def event_UIA_notification (self , obj , nextHandler , displayString = None , activityId = None , ** kwargs ):
81+ # When no results shortcuts such as number row keys are pressed, display content will be announced.
82+ # #13383: it might be possible that the next command is a calculation shortcut such as S for sine.
83+ # Therefore, clear no result gestures flag from the app module while storing a copy of the flag here.
84+ # The event handler copy is used to handle the overall notification announcement later.
85+ doNotAnnounceCalculatorResults = self ._noCalculatorResultsGesturePressed
86+ self ._noCalculatorResultsGesturePressed = False
7887 calculatorVersion = int (self .productVersion .split ("." )[0 ])
7988 # #12268: for "DisplayUpdated", announce display strings in braille no matter what they are.
8089 # There are other activity Id's such as "MemorySlotAdded" and "MemoryCleared"
@@ -94,6 +103,7 @@ def event_UIA_notification(self, obj, nextHandler, displayString=None, activityI
94103 resultElement
95104 and resultElement .firstChild
96105 and resultElement .firstChild .UIAAutomationId in noCalculatorEntryAnnouncements
106+ and doNotAnnounceCalculatorResults
97107 ):
98108 return
99109 nextHandler ()
@@ -112,6 +122,11 @@ def script_calculatorResult(self, gesture):
112122 # To prevent double focus announcement, check where we are.
113123 focus = api .getFocusObject ()
114124 gesture .send ()
125+ # #13383: later Calculator releases use UIA notification event to announce results.
126+ # While the exact version that introduced UIA notification event cannot be found easily,
127+ # it is definitely used in version 10.1908 and later.
128+ if self .productVersion >= "10.1908" :
129+ return
115130 # In redstone, calculator result keeps firing name change,
116131 # so tell it to do so if and only if enter has been pressed.
117132 self ._shouldAnnounceResult = True
@@ -125,3 +140,12 @@ def script_calculatorResult(self, gesture):
125140 if isinstance (resultsScreen , UIA ) and resultsScreen .UIAElement .cachedClassName == "LandmarkTarget" :
126141 # And no, do not allow focus to move.
127142 queueHandler .queueFunction (queueHandler .eventQueue , ui .message , resultsScreen .firstChild .name )
143+
144+ # Handle both number row and numpad with num lock on.
145+ @scriptHandler .script (
146+ gestures = [f"kb:{ i } " for i in range (10 )]
147+ + [f"kb:numLockNumpad{ i } " for i in range (10 )]
148+ )
149+ def script_doNotAnnounceCalculatorResults (self , gesture ):
150+ gesture .send ()
151+ self ._noCalculatorResultsGesturePressed = True
0 commit comments