Repository: nvaccess/nvda

Issue:
German Win7: LTR and RTL characters still exist in Properties Window (explorer.exe) and in the Taskbar Clock
NVDA-Version: NVDA 2018.2 RC2, Portable, Win7x64, German UI (de-AT)

See issue #5729 and PR #5751 and PR #8316 

Date formats:
+ Taskbar clock: hh:mm, Ldddd, Ldd.Lmm.Lyyyy
+ Properties window: Ldddd, Ldd. Lmmmm Lyyyy, RLhh:mm:ss
  Hint: Open the properties window of a file/folder in the Windows Explorer.

L = U+200E (LTR), R = U+200F (RTL)

Update No. 1: Windows Explorer » Detail View » Last modified field » date format:
+ NVDA 2018.1: Ldd.Lmm.Lyyyy RLhh:mm
+ NVDA 2018.2 RC2: dd.mm.yyyy hh:mm

This works as expected. And there is no issue with an empty size field in this view in Windows Explorer.

Update No. 2: Systemsteuerung\Programme\Programme und Funktionen (Control Panel\Software\Software and features) » Detail View » Date of Installation field » date format:
+ NVDA 2018.1: Ldd.Lmm.Lyyyy
+ NVDA 2018.2 RC2: dd.mm.yyyy

This also works as expected.


Discussion:
Update: This issue still exists in NVDA 2018.2 RC3.
Additional date format in the Windows Explorer properties window:
+ LHeute, L07. LJuni L2018, RLVor 25 Minuten (translated to EN: LToday, Ldd. Lmmmm Lyyyy, RLmm minutes ago)
  Hint: "ago" stands for "Vor". In German it stands before the amount of the minutes, not after.
cc @dkager, would you be able too look into this?
Off the top of my head I excluded some cases, such as the clock, from the PR to make it less complex. Liblouis braille tables can also filter these characters.
Eliminating U+200E and U+200F at this early point of process has not only effects to the braille output, it also changes the pronunciation of the TTS depending of the current used synthesizer. Well, and for me: I added `sign \x200e 12378` and `sign \x200f 45678` in the file "de-de-comp8.ctb" years ago. So, the braille output alone isn't the point.

Well, after a quick look in PR #5751 I would say that this issue here (#8361) should be part of NVDA 2018.3 (or later) because it isn't critical at all.

Sadly the changelog entry in 2018.2 RC3 still says something complete different at all. In other words: the changelog entry should be changed from
> • NVDA no longer reports (LTR and RTL marks) in Braille or per-character speech when accessing the clock in recent versions of Windows. (#5729)

to something more like "Filter LTR and RTL marks from list view items" (in the Windows Explorer) because this seems to be the current state. (I know that changing the changelog entry will have no effect in the translated changelogs to NVDA 2018.2 at this late point.)
Is it still reproducible in NVDA 2018.2? I get the right reportings by speech at least. But I don't habe a braille display to test it in braille.
Yep, the issue still exists in NVDA 2018.2. You can check this out without a braille display in moving the NVDA-Cursor by character.
Hello, oh I didn't try this. Yes I can confirm.

Resolving patch:
diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py
--- a/source/NVDAObjects/IAccessible/__init__.py
+++ b/source/NVDAObjects/IAccessible/__init__.py
@@ -1717,20 +1717,33 @@ def _get_isPresentableFocusAncestor(self):
 		self.isPresentableFocusAncestor = res = super(Groupbox, self).isPresentableFocusAncestor
 		return res
 
+CHAR_LTR_MARK = u'\u200E'
+CHAR_RTL_MARK = u'\u200F'
 class TrayClockWClass(IAccessible):
 	"""
 	Based on NVDAObject but the role is changed to clock.
+	Depending on the version of Windows name or value contains left-to-right or right-to-left characters, so remove them from both.
 	"""
 
 	def _get_role(self):
+		# On Windows 10 Anniversary update and later the text 'clock' is included in the name so having clock in the control type is redundant.
+		if super(TrayClockWClass, self).value is None:
+			return controlTypes.ROLE_BUTTON
 		return controlTypes.ROLE_CLOCK
 
 	def _get_name(self):
-		# #4364 On some versions of Windows name contains redundant information that is available either in the role or the value, however on Windows 10 Anniversary Update and later the value is empty, so we cannot simply dismiss the name.
+	# #4364 On some versions of Windows name contains redundant information that is available either in the role or the value, however on Windows 10 Anniversary Update and later the value is empty, so we cannot simply dismiss the name.
 		if super(TrayClockWClass, self).value is None:
-			return super(TrayClockWClass, self).name
+			clockName = super(TrayClockWClass, self).name
+			return clockName.replace(CHAR_LTR_MARK,'').replace(CHAR_RTL_MARK,'')
 		return None
 
+	def _get_value(self):
+		clockValue = super(TrayClockWClass, self).value
+		if clockValue is not None:
+			clockValue = clockValue.replace(CHAR_LTR_MARK,'').replace(CHAR_RTL_MARK,'')
+		return clockValue
+
 class OutlineItem(IAccessible):
 
 	def _get_value(self):
@@ -1907,7 +1920,7 @@ def event_alert(self):
 	(None,oleacc.ROLE_SYSTEM_ALERT):"Dialog",
 	(None,oleacc.ROLE_SYSTEM_PROPERTYPAGE):"Dialog",
 	(None,oleacc.ROLE_SYSTEM_GROUPING):"Groupbox",
-	("TrayClockWClass",oleacc.ROLE_SYSTEM_CLIENT):"TrayClockWClass",
+	("TrayClockWClass",oleacc.ROLE_SYSTEM_PUSHBUTTON):"TrayClockWClass",
 	("TrayClockWClass",oleacc.ROLE_SYSTEM_CLOCK):"TrayClockWClass",
 	("TRxRichEdit",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRxRichEdit",
 	(None,oleacc.ROLE_SYSTEM_OUTLINEITEM):"OutlineItem",
diff --git a/source/appModules/dllhost.py b/source/appModules/dllhost.py
new file mode 100644
--- /dev/null
+++ b/source/appModules/dllhost.py
@@ -0,0 +1,20 @@
+# -*- coding: UTF-8 -*-
+# A part of NonVisual Desktop Access (NVDA)
+# Copyright (C) 2018 NV Access Limited, Łukasz Golonka
+# This file may be used under the terms of the GNU General Public License, version 2 or later.
+# For more details see: https://www.gnu.org/licenses/gpl-2.0.html
+
+""" Under older builds of Windows 10 (from RTM release to Creators Update) dllhost is used to display a properties window. 
+Read-Only edit boxes in it can contain dates that include unwanted left-to-right and right-to-left indicator characters.
+This simply imports a proper class from the explorer app module, and maps it to a edit control.
+"""
+
+import appModuleHandler
+from .explorer import ReadOnlyEditBox
+
+class AppModule(appModuleHandler.AppModule):
+
+	def chooseNVDAObjectOverlayClasses(self, obj, clsList):
+		windowClass = obj.windowClassName
+		if windowClass == "Edit":
+			clsList.insert(0, ReadOnlyEditBox)
diff --git a/source/appModules/explorer.py b/source/appModules/explorer.py
--- a/source/appModules/explorer.py
+++ b/source/appModules/explorer.py
@@ -178,6 +178,15 @@ def _get_value(self):
 			return value
 		return value.replace(CHAR_LTR_MARK,'').replace(CHAR_RTL_MARK,'')
 
+class ReadOnlyEditBox(IAccessible):
+#Used for read-only edit boxes in a properties window.
+#These can contain dates that include unwanted left-to-right and right-to-left indicator characters.
+
+	def _get_windowText(self):
+		windowText = super(ReadOnlyEditBox, self).windowText
+		if windowText is not None and controlTypes.STATE_READONLY in self.states:
+			return windowText.replace(CHAR_LTR_MARK,'').replace(CHAR_RTL_MARK,'')
+		return windowText
 
 class AppModule(appModuleHandler.AppModule):
 
@@ -208,6 +217,10 @@ def chooseNVDAObjectOverlayClasses(self, obj, clsList):
 					toolbarParent = None
 				if toolbarParent and toolbarParent.windowClassName == "SysPager":
 					clsList.insert(0, NotificationArea)
+			return 
+
+		if windowClass == "Edit":
+			clsList.insert(0, ReadOnlyEditBox)
 			return # Optimization: return early to avoid comparing class names and roles that will never match.
 
 		if windowClass == "SysListView32" and role == controlTypes.ROLE_MENUITEM:


Test patch: