Repository: nvaccess/nvda

Issue:
current status is announced multiple times by NVDA
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Steps to reproduce:
1. Open this example on a windows FireFox browser tab, https://jsfiddle.net/AnthonyYY/xpvt214o/952936/
2. Open NVDA and open its speech viewer.
2. in the JSFiddle's `result` panel, use keydown `tab` twice to navigate to the next menu-item.
3. hit `enter` key to activate to target menu item.
4. check the speech viewer
### Actual behavior:
NVDA reads aria-current menu item's current status twice.
### Expected behavior:
when hitting `enter` key to activate a menu-item. clicked menu item's current status is report once only.
### System configuration:
#### NVDA Installed/portable/running from source:
Installed
#### NVDA version:
2018.3.2
#### Windows version:
Window 10 Pro
#### Name and version of other software in use when reproducing the issue:
FireFox: version 63.0.1 (32)
#### Other information about your system:

### Other questions:

#### Does the issue still occur after restarting your PC?
Yes
#### Have you tried any other versions of NVDA?
Yes


Discussion:
Previously i thought  it's an issue of react-router, for reference https://github.com/ReactTraining/react-router/issues/5507. After reproduced it by jQuery found that it may be caused by NVDA.
We have a similar issue with role="treeview" / role="treeitem" and aria-current. "current" is repeated several times up to 5. It really gets annoying quickly.
cc: @jcsteh, @MarcoZehe 
This is a bug in NVDA, not in browsers. I figured out why this is happening, so I'll submit a PR shortly.

Resolving patch:
diff --git a/source/NVDAObjects/IAccessible/ia2Web.py b/source/NVDAObjects/IAccessible/ia2Web.py
--- a/source/NVDAObjects/IAccessible/ia2Web.py
+++ b/source/NVDAObjects/IAccessible/ia2Web.py
@@ -18,6 +18,8 @@
 from . import IAccessible
 from .ia2TextMozilla import MozillaCompoundTextInfo
 import aria
+import api
+import speech
 
 class Ia2Web(IAccessible):
 	IAccessibleTableUsesTableCellIndexAttrib=True
@@ -80,6 +82,15 @@ def _get_landmark(self):
 			return landmark
 		return super().landmark
 
+	def event_IA2AttributeChange(self):
+		super().event_IA2AttributeChange()
+		if self is api.getFocusObject():
+			# Report aria-current if it changed.
+			speech.speakObjectProperties(
+				self, current=True, reason=controlTypes.REASON_CHANGE)
+		# super calls event_stateChange which updates braille, so no need to
+		# update braille here.
+
 
 class Document(Ia2Web):
 	value = None
diff --git a/source/speech/__init__.py b/source/speech/__init__.py
--- a/source/speech/__init__.py
+++ b/source/speech/__init__.py
@@ -297,6 +297,10 @@ def speakObjectProperties(  # noqa: C901
 		elif name.startswith('positionInfo_') and value:
 			if positionInfo is None:
 				positionInfo=obj.positionInfo
+		elif value and name == "current":
+			# getPropertiesSpeech names this "current", but the NVDAObject property is
+			# named "isCurrent".
+			newPropertyValues['current'] = obj.isCurrent
 		elif value:
 			# Certain properties such as row and column numbers have presentational versions, which should be used for speech if they are available.
 			# Therefore redirect to those values first if they are available, falling back to the normal properties if not.
@@ -350,7 +354,6 @@ def speakObjectProperties(  # noqa: C901
 			newPropertyValues["_tableID"]=obj.tableID
 		except NotImplementedError:
 			pass
-	newPropertyValues['current']=obj.isCurrent
 	if allowedProperties.get('placeholder', False):
 		newPropertyValues['placeholder']=obj.placeholder
 	# When speaking an object due to a focus change, the 'selected' state should not be reported if only one item is selected.
@@ -437,7 +440,8 @@ def speakObject(  # noqa: C901
 		"rowHeaderText": True,
 		"columnHeaderText": True,
 		"rowSpan": True,
-		"columnSpan": True
+		"columnSpan": True,
+		"current": True
 	}
 
 	if reason==controlTypes.REASON_FOCUSENTERED:


Test patch: