Repository: nvaccess/nvda

Issue:
Visual Studio: IntelliSense tooltips reported twice
### Steps to reproduce:
1. Open Visual Studio 2019
2. Open a C# project
3. Enable reporting of Tooltips
4. Trigger an IntelliSense autocomplete suggestion by typing something.
5. Arrow through the suggestions

### Actual behavior:
The selected item is announced, followed by twice the tooltip.

### Expected behavior:
The selected item is announced, followed by once the tooltip.

### System configuration
#### NVDA installed/portable/running from source:
Installed

#### NVDA version:
alpha-20957

#### Windows version:
Windows 10 2004

#### Name and version of other software in use when reproducing the issue:
Visual Studio 2019 16.7.3 Enterprise

### 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?
Yes


Discussion:
@josephsl Have you seen this behavior in more applications? What do you think would be the bst way to work around this? I'd like to avoid a check like _shouldAllowUIALiveRegionEvent if possible

Resolving patch:
diff --git a/source/NVDAObjects/UIA/VisualStudio.py b/source/NVDAObjects/UIA/VisualStudio.py
--- a/source/NVDAObjects/UIA/VisualStudio.py
+++ b/source/NVDAObjects/UIA/VisualStudio.py
@@ -7,10 +7,11 @@
 available in Visual Studio and SQL Server Management Studio.
 """
 
-from . import UIA
+from . import UIA, ToolTip
 import speech
 import braille
 import api
+import time
 
 
 class IntelliSenseItem(UIA):
@@ -53,6 +54,34 @@ class IntelliSenseLiveRegion(UIA):
 }
 
 
+class CompletionToolTip(ToolTip):
+	""" A tool tip for which duplicate open events can be fired.
+	"""
+
+	#: Keeps track of the last ToolTipOpened event (text, time)
+	_lastToolTipOpenedInfo = (None, None)
+	#: The duplicate tooltip events will be dropped within this time window
+	_preventDuplicateToolTipSeconds = 0.2
+
+	def event_UIA_toolTipOpened(self):
+		oldText, oldTime = self._lastToolTipOpenedInfo
+		newText = self.name
+		newTime = time.time()
+		self.__class__._lastToolTipOpenedInfo = (newText, newTime)
+		withinPossibleDupToolTipTimeWindow = (
+			oldTime is not None
+			and (newTime - oldTime) < self._preventDuplicateToolTipSeconds
+		)
+		if newText == oldText and withinPossibleDupToolTipTimeWindow:
+			# Tool-tip event suspected to be a duplicate, drop the event.
+			# - Users attempting to rapidly re-announce tool-tips may
+			#   have the announcement erroneously  suppressed
+			# - Users on slower systems (or systems under load) may still
+			#   receive duplicate announcements
+			return
+		super().event_UIA_toolTipOpened()
+
+
 def findExtraOverlayClasses(obj, clsList):
 	if obj.UIAAutomationId in _INTELLISENSE_LIST_AUTOMATION_IDS:
 		clsList.insert(0, IntelliSenseList)
@@ -64,3 +93,5 @@ def findExtraOverlayClasses(obj, clsList):
 		and isinstance(obj.previous.previous, IntelliSenseList)
 	):
 		clsList.insert(0, IntelliSenseLiveRegion)
+	elif obj.UIAAutomationId == "completion tooltip":
+		clsList.insert(0, CompletionToolTip)


Test patch: