Repository: nvaccess/nvda

Issue:
Mark globalVars for deprecation
<!-- Please read and fill in the following template, for an explanation of the sections see:
https://github.com/nvaccess/nvda/blob/master/devDocs/githubPullRequestTemplateExplanationAndExamples.md
Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. 

Please initially open PRs as a draft. See https://github.com/nvaccess/nvda/wiki/Contributing
-->

### Link to issue number:
Supersedes #14037 
See also #14049

### Summary of the issue:

#14037 was closed because there was no way to preserve backwards compatibility.
This is the case for any module level variable which the NVDA API expects to support assignment (see also #14049).

`globalVars` contains many NVDA state variables which should not be changed by add-on authors.
As a result, `globalVars` should eventually be deprecated, in favour of encapsulation of these variables.
This will make retaining backwards compatibility possible in the future.

### Description of user facing changes
None

### Description of development approach
Added a deprecation warning and strategy to the docstring of `globalVars`.

Encapsulated some less used `globalVars` to provide an example of what the future API should look like.

`runningAsSource` was moved from `globalVars` as this is an unreleased variable. (#14015)
`_allowDeprecatedAPI` was moved as it is internal code.

### Testing strategy:
None

### Known issues with pull request:
None

### Change log entries:
None

### Code Review Checklist:

<!--
This checklist is a reminder of things commonly forgotten in a new PR.
Authors, please do a self-review of this pull-request.
Check items to confirm you have thought about the relevance of the item.
Where items are missing (eg unit / system tests), please explain in the PR.
To check an item `- [ ]` becomes `- [x]`, note spacing.
You can also check the checkboxes after the PR is created.
A detailed explanation of this checklist is available here:
https://github.com/nvaccess/nvda/blob/master/devDocs/githubPullRequestTemplateExplanationAndExamples.md#code-review-checklist
-->

- [x] Pull Request description:
  - description is up to date
  - change log entries
- [x] Testing:
  - Unit tests
  - System (end to end) tests
  - Manual testing
- [x] API is compatible with existing add-ons.
- [x] Documentation:
  - User Documentation
  - Developer / Technical Documentation
  - Context sensitive help for GUI changes
- [x] UX of all users considered:
  - Speech 
  - Braille
  - Low Vision
  - Different web browsers
  - Localization in other languages / culture than English
- [x] Security precautions taken.



Discussion:

Resolving patch:
diff --git a/source/braille.py b/source/braille.py
--- a/source/braille.py
+++ b/source/braille.py
@@ -2624,8 +2624,7 @@ def _getTryPorts(
 					yield match
 
 	#: Global input gesture map for this display driver.
-	#: @type: L{inputCore.GlobalGestureMap}
-	gestureMap = None
+	gestureMap: Optional[inputCore.GlobalGestureMap] = None
 
 	@classmethod
 	def _getModifierGestures(cls, model=None):
diff --git a/source/inputCore.py b/source/inputCore.py
--- a/source/inputCore.py
+++ b/source/inputCore.py
@@ -13,7 +13,16 @@
 import os
 import weakref
 import time
-from typing import Dict, Any, Tuple, List, Union
+from typing import (
+	Any,
+	Dict,
+	Generator,
+	List,
+	Optional,
+	Tuple,
+	TypeVar,
+	Union,
+)
 from gui import blockAction
 import configobj
 from speech import sayAll
@@ -32,6 +41,16 @@
 import controlTypes
 import winKernel
 
+
+InputGestureBindingClassT = TypeVar("InputGestureBindingClassT")
+ScriptNameT = str
+InputGestureScriptT = Tuple[InputGestureBindingClassT, Optional[ScriptNameT]]
+"""
+The Python class and script name for each script;
+the script name may be C{None} indicating that the gesture should be unbound for this class.
+"""
+
+
 #: Script category for emulated keyboard keys.
 # Translators: The name of a category of NVDA commands.
 SCRCAT_KBEMU = _("Emulated system keyboard keys")
@@ -321,13 +340,11 @@ def update(self, entries):
 						self.lastUpdateContainedError = True
 						continue
 
-	def getScriptsForGesture(self, gesture):
+	def getScriptsForGesture(self, gesture: str) -> Generator[InputGestureScriptT, None, None]:
 		"""Get the scripts associated with a particular gesture.
 		@param gesture: The gesture identifier.
-		@type gesture: str
 		@return: The Python class and script name for each script;
 			the script name may be C{None} indicating that the gesture should be unbound for this class.
-		@rtype: generator of (class, str)
 		"""
 		try:
 			scripts = self._map[gesture]
@@ -845,9 +862,10 @@ def getDisplayTextForGestureIdentifier(identifier):
 		raise
 		raise LookupError("Couldn't get display text for identifier: %s" % identifier)
 
+
 #: The singleton input manager instance.
-#: @type: L{InputManager}
-manager = None
+manager: Optional[InputManager] = None
+
 
 def initialize():
 	"""Initializes input core, creating a global L{InputManager} singleton.
diff --git a/source/scriptHandler.py b/source/scriptHandler.py
--- a/source/scriptHandler.py
+++ b/source/scriptHandler.py
@@ -1,5 +1,5 @@
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2007-2022 NV Access Limited, Babbage B.V., Julien Cochuyt
+# Copyright (C) 2007-2022 NV Access Limited, Babbage B.V., Julien Cochuyt, Leonard de Ruijter
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -8,7 +8,6 @@
 	Optional,
 	Iterator,
 	List,
-	Set,
 )
 import time
 import weakref
@@ -49,8 +48,13 @@ def _makeKbEmulateScript(scriptName):
 def _getObjScript(
 		obj: "NVDAObjects.NVDAObject",
 		gesture: "inputCore.InputGesture",
-		globalMapScripts: Set[_ScriptFunctionT],
+		globalMapScripts: List["inputCore.InputGestureScriptT"],
 ) -> Optional[_ScriptFunctionT]:
+	"""
+	@param globalMapScripts: An ordered list of scripts.
+	The list is ordered by resolution priority,
+	the first map in the list should be used to resolve the script first.
+	"""
 	# Search the scripts from the global gesture maps.
 	for cls, scriptName in globalMapScripts:
 		if isinstance(obj, cls):
@@ -72,15 +76,20 @@ def _getObjScript(
 		log.exception()
 
 
-def getGlobalMapScripts(gesture: "inputCore.InputGesture") -> Set[_ScriptFunctionT]:
-	globalMapScripts: Set[_ScriptFunctionT] = set()
+def getGlobalMapScripts(gesture: "inputCore.InputGesture") -> List["inputCore.InputGestureScriptT"]:
+	"""
+	@returns: An ordered list of scripts.
+	The list is ordered by resolution priority,
+	the first map in the list should be used to resolve scripts first.
+	"""
+	globalMapScripts: List["inputCore.InputGestureScriptT"] = []
 	globalMaps = [inputCore.manager.userGestureMap, inputCore.manager.localeGestureMap]
 	globalMap = braille.handler.display.gestureMap if braille.handler and braille.handler.display else None
 	if globalMap:
 		globalMaps.append(globalMap)
 	for globalMap in globalMaps:
 		for identifier in gesture.normalizedIdentifiers:
-			globalMapScripts.update(globalMap.getScriptsForGesture(identifier))
+			globalMapScripts.extend(globalMap.getScriptsForGesture(identifier))
 	return globalMapScripts
 
 


Test patch: