Repository: nvaccess/nvda

Issue:
System focus does not move to edit field when "Automatic focus mode for caret movement" is enabled.
<!-- Please read the text in this edit field before filling it in.
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
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. 
-->

### Steps to reproduce:
1: Enable the option "Automatic focus mode for caret movement" in the browse mode settings of NVDA.
2: Go to a website with edit fields.
3: Use the arrow keys to go to an edit field.

### Actual behavior:
Focus mode is turned on, but system focus is not moved to the edit field. Because of this it is not possible to type in the edit field. To be able to type text anyway, you must switch to browse mode and then press enter or space. Then focus mode is turned on again and the system focus is moved to the edit field.

### Expected behavior:
When you get to an edit field with the arrow keys, NVDA switches to focus mode and the system focus moves to the edit field.

### System configuration
#### NVDA installed/portable/running from source:
Installed
#### NVDA version:
2020.3beta3
#### Windows version:
Windows 10 1909 (64-bit) build 18363.1082
#### Name and version of other software in use when reproducing the issue:
Microsoft Edge 85.0.564.51 and Firefox 80.0.1
#### Other information about your system:

### 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.
In previous versions of NVDA this works as expected, the problem is caused by changes in NVDA2020.3.
#### If addons are disabled, is your problem still occuring?
Yes
#### Did you try to run the COM registry fixing tool in NVDA menu / tools?
No


Discussion:

Resolving patch:
diff --git a/source/browseMode.py b/source/browseMode.py
--- a/source/browseMode.py
+++ b/source/browseMode.py
@@ -1,5 +1,6 @@
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2007-2020 NV Access Limited, Babbage B.V. Thomas Stivers
+# Copyright (C) 2007-2020 NV Access Limited, Babbage B.V., James Teh, Leonard de Ruijter,
+# Thomas Stivers
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -1328,18 +1329,24 @@ def _set_selection(self, info, reason=controlTypes.REASON_CARET):
 			if not obj:
 				log.debugWarning("Invalid NVDAObjectAtStart")
 				return
-			followBrowseModeFocus= config.conf["virtualBuffers"]["autoFocusFocusableElements"]
 			if obj==self.rootNVDAObject:
 				return
-			if followBrowseModeFocus:
-				if focusObj and not eventHandler.isPendingEvents("gainFocus") and focusObj!=self.rootNVDAObject and focusObj != api.getFocusObject() and self._shouldSetFocusToObj(focusObj):
-					focusObj.setFocus()
 			obj.scrollIntoView()
 			if self.programmaticScrollMayFireEvent:
 				self._lastProgrammaticScrollTime = time.time()
-		self.passThrough=self.shouldPassThrough(focusObj,reason=reason)
-		# Queue the reporting of pass through mode so that it will be spoken after the actual content.
-		queueHandler.queueFunction(queueHandler.eventQueue, reportPassThrough, self)
+		if focusObj:
+			self.passThrough = self.shouldPassThrough(focusObj, reason=reason)
+			if (
+				not eventHandler.isPendingEvents("gainFocus")
+				and focusObj != self.rootNVDAObject
+				and focusObj != api.getFocusObject()
+				and self._shouldSetFocusToObj(focusObj)
+			):
+				followBrowseModeFocus = config.conf["virtualBuffers"]["autoFocusFocusableElements"]
+				if followBrowseModeFocus or self.passThrough:
+					focusObj.setFocus()
+			# Queue the reporting of pass through mode so that it will be spoken after the actual content.
+			queueHandler.queueFunction(queueHandler.eventQueue, reportPassThrough, self)
 
 	def _shouldSetFocusToObj(self, obj):
 		"""Determine whether an object should receive focus.
diff --git a/source/synthDrivers/sapi5.py b/source/synthDrivers/sapi5.py
--- a/source/synthDrivers/sapi5.py
+++ b/source/synthDrivers/sapi5.py
@@ -1,7 +1,6 @@
 # -*- coding: UTF-8 -*-
-# synthDrivers/sapi5.py
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2006-2020 NV Access Limited, Peter Vágner, Aleksey Sadovoy
+# Copyright (C) 2006-2017 NV Access Limited, Peter Vágner, Aleksey Sadovoy
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -364,11 +363,6 @@ def outputTags():
 		tagsChanged[0] = True
 		outputTags()
 
-		# Some SAPI5 synthesizers complete speech sequence just after the last text is said
-		# and ignore any indexes passed afterward.
-		# Therefore we add the pause of 1ms at the end of each sequence.
-		textList.append('<silence msec="1" />')
-		# Join textList to create xml document passed to synthesizer
 		text = "".join(textList)
 		flags = constants.SVSFIsXML | constants.SVSFlagsAsync
 		self.tts.Speak(text, flags)


Test patch: