Repository: nvaccess/nvda

Issue:
How to prevent NVDA to overwrite touchscreen configurations on Windows
<!--
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:
When NVDA is on, it overwrites a set of predefined touch and gestures configurations for touchscreens, so what was before a single tap action becomes a fast double tap one. I need to prevent NVDA from overwriting some default settings on Windows.

I already tried removing "tap (Touch screen)" from "Input Gestures" under "Preferences" option, but it only stopped dictating, I still have to double tap to perform an action.

### System configuration
I'm using windows 10

#### NVDA version:
2019.1.1

#### Windows version:
Windows 10



Discussion:
What happens if you press NVDA+F2 before performing the touch gesture?
Hi @DrSooom! I believe the issue here is that there ain't a keyboard to press F2. What @simonesilva is asking is to disable double tap feature and keep it disabled when restarting Windows in a touch only device.

By-the-way, what is the "NVDA" from "NVDA+F2", is it a special key from a specific device?
On Mon, 10 Jun 2019, Alejo Ceballos wrote:

> By-the-way, what is the "NVDA" from "NVDA+F2", is it a special key from a specific device?

A screenreader needs to handle many commands from the user--to read lines, 
characters, words, windows, etc.; to move to different parts of the screen; to 
change how certain information is being presented because more or less detail is 
needed; and dozens of more things. So a special modifier key must be used, since 
the alt, control, and other such keys are already used by most applications.

Since we're talking about the NVDA screen reader here, that key is called 
"NVDA". It is usually the insert key on the keyboard, and most users also remap 
the capslock key to serve as an additional NVDA key.

So, for example, pressing NVDA+1, which just means capslock and the number 1, 
enters key describer mode, wherein NVDA describes what all the other keys and 
key combinations do. NVDA+q exits the screenreader. NVDA+shift+g is a quick 
shortcut to open the screenreader's general settings dialog. NVDA+n brings up 
the screenreader main menu. And so on.


Resolving patch:
diff --git a/source/config/configSpec.py b/source/config/configSpec.py
--- a/source/config/configSpec.py
+++ b/source/config/configSpec.py
@@ -161,6 +161,7 @@
 	autoFocusFocusableElements = boolean(default=True)
 
 [touch]
+	enabled = boolean(default=true)
 	touchTyping = boolean(default=False)
 
 #Settings for document reading (such as MS Word and wordpad)
diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py
--- a/source/gui/settingsDialogs.py
+++ b/source/gui/settingsDialogs.py
@@ -2217,14 +2217,21 @@ class TouchInteractionPanel(SettingsPanel):
 	title = _("Touch Interaction")
 
 	def makeSettings(self, settingsSizer):
+		sHelper = guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
+		# Translators: This is the label for a checkbox in the
+		# touch interaction settings panel.
+		touchSupportEnableLabel = _("Enable touch interaction support")
+		self.enableTouchSupportCheckBox = sHelper.addItem(wx.CheckBox(self, label=touchSupportEnableLabel))
+		self.enableTouchSupportCheckBox.SetValue(config.conf["touch"]["enabled"])
 		# Translators: This is the label for a checkbox in the
 		# touch interaction settings panel.
-		self.touchTypingCheckBox=wx.CheckBox(self,label=_("&Touch typing mode"))
+		self.touchTypingCheckBox = sHelper.addItem(wx.CheckBox(self, label=_("&Touch typing mode")))
 		self.touchTypingCheckBox.SetValue(config.conf["touch"]["touchTyping"])
-		settingsSizer.Add(self.touchTypingCheckBox,border=10,flag=wx.BOTTOM)
 
 	def onSave(self):
-		config.conf["touch"]["touchTyping"]=self.touchTypingCheckBox.IsChecked()
+		config.conf["touch"]["enabled"] = self.enableTouchSupportCheckBox.IsChecked()
+		config.conf["touch"]["touchTyping"] = self.touchTypingCheckBox.IsChecked()
+		touchHandler.setTouchSupport(config.conf["touch"]["enabled"])
 
 class UwpOcrPanel(SettingsPanel):
 	# Translators: The title of the Windows 10 OCR panel.
diff --git a/source/touchHandler.py b/source/touchHandler.py
--- a/source/touchHandler.py
+++ b/source/touchHandler.py
@@ -1,8 +1,7 @@
-#touchHandler.py
-#A part of NonVisual Desktop Access (NVDA)
-#This file is covered by the GNU General Public License.
-#See the file COPYING for more details.
-#Copyright (C) 2012-2018 NV Access Limited, Joseph Lee, Babbage B.V.
+# A part of NonVisual Desktop Access (NVDA)
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
+# Copyright (C) 2012-2020 NV Access Limited, Joseph Lee, Babbage B.V.
 
 """handles touchscreen interaction (Windows 8 and later).
 Used to provide input gestures for touchscreens, touch modes and other support facilities.
@@ -294,30 +293,57 @@ def notifyInteraction(self, obj):
 
 handler=None
 
-def touchSupported():
+
+def touchSupported(debugLog: bool = False):
 	"""Returns if the system and current NVDA session supports touchscreen interaction.
+	@param debugLog: Whether to log additional details about touch support to the NVDA log.
 	"""
 	if not config.isInstalledCopy() and not config.isAppX:
-		log.debugWarning("Touch only supported on installed copies")
+		if debugLog:
+			log.debugWarning("Touch only supported on installed copies")
 		return False
-	if (winVersion.winVersion.major*10+winVersion.winVersion.minor)<62:
-		log.debugWarning("Touch only supported on Windows 8 and higher")
+	if winVersion.winVersion.platform_version < (6, 2, 9200):
+		if debugLog:
+			log.debugWarning("Touch only supported on Windows 8 and higher")
 		return False
 	maxTouches=windll.user32.GetSystemMetrics(SM_MAXIMUMTOUCHES)
 	if maxTouches<=0:
-		log.debugWarning("No touch devices found")
+		if debugLog:
+			log.debugWarning("No touch devices found")
 		return False
 	return True
 
-def initialize():
+
+def setTouchSupport(enable: bool):
 	global handler
 	if not touchSupported():
 		raise NotImplementedError
-	handler=TouchHandler()
-	log.debug("Touch support initialized. maximum touch inputs: %d"%windll.user32.GetSystemMetrics(SM_MAXIMUMTOUCHES))
+	if not handler and enable:
+		handler = TouchHandler()
+		log.debug("Touch support enabled.")
+	elif handler and not enable:
+		handler.terminate()
+		handler = None
+		log.debug("Touch support disabled.")
+
+
+def handlePostConfigProfileSwitch():
+	setTouchSupport(config.conf["touch"]["enabled"])
+
+
+def initialize():
+	global handler
+	if not touchSupported(debugLog=True):
+		raise NotImplementedError
+	log.debug(
+		"Touchscreen detected, maximum touch inputs: %d" % winUser.user32.GetSystemMetrics(SM_MAXIMUMTOUCHES)
+	)
+	config.post_configProfileSwitch.register(handlePostConfigProfileSwitch)
+	setTouchSupport(config.conf["touch"]["enabled"])
 
 def terminate():
 	global handler
+	config.post_configProfileSwitch.unregister(handlePostConfigProfileSwitch)
 	if handler:
 		handler.terminate()
 		handler=None


Test patch: