Repository: nvaccess/nvda

Issue:
The gesture mappings for the Hims Braille Edge follow the global setting and not the model-specific map
The user guide as well as the NVDA settings both mention two alternative gesture mappings for the hims displays: a global one and one specific to the model of the display.

I'm using a Braille Edge and currently NVDA behaves as if the global setting was the one to be used when in fact the Braille Edge should be. This leads to conflicts, E.G. the gesture for the ctrl key assigned to Braille Edge displays is the third function key, F3; however, when I press it, NVDA records and executes the tab key command.

I've checked it with a fresh, portable copy of 2018.1 with no custom settings.


Discussion:
I'm going to investigate this next week. I consider this a personal p2, given it is an annoying bug and probably not very difficult to fix. I will self assign this.

Resolving patch:
diff --git a/source/braille.py b/source/braille.py
--- a/source/braille.py
+++ b/source/braille.py
@@ -2243,16 +2243,16 @@ def _get_keyNames(self):
 	#: Compiled regular expression to match an identifier including an optional model name
 	#: The model name should be an alphanumeric string without spaces.
 	#: @type: RegexObject
-	ID_PARTS_REGEX = re.compile(r"br\((\w+)(\.(\w+))?\):([\w+]+)", re.U)
+	ID_PARTS_REGEX = re.compile(r"br\((\w+)(?:\.(\w+))?\):([\w+]+)", re.U)
 
 	@classmethod
 	def getDisplayTextForIdentifier(cls, identifier):
-		idParts = cls.ID_PARTS_REGEX.search(identifier)
+		idParts = cls.ID_PARTS_REGEX.match(identifier)
 		if not idParts:
 			log.error("Invalid braille gesture identifier: %s"%identifier)
 			return handler.display.description, "malformed:%s"%identifier
-		modelName = idParts.group(3)
-		key = idParts.group(4)
+		modelName = idParts.group(2)
+		key = idParts.group(3)
 		if modelName: # The identifier contains a model name
 			return handler.display.description, "{modelName}: {key}".format(
 				modelName=modelName, key=key
diff --git a/source/brailleDisplayDrivers/hims.py b/source/brailleDisplayDrivers/hims.py
--- a/source/brailleDisplayDrivers/hims.py
+++ b/source/brailleDisplayDrivers/hims.py
@@ -707,7 +707,8 @@ class KeyInputGesture(braille.BrailleDisplayGesture, brailleInput.BrailleInputGe
 
 	def __init__(self, model, keys):
 		super(KeyInputGesture, self).__init__()
-		self.model=model.name
+		# Model identifiers should not contain spaces.
+		self.model=model.name.replace(" ", "")
 		self.keys = keys
 		self.keyNames = names = set()
 		isBrailleInput = True


Test patch:
diff --git a/tests/unit/test_braille.py b/tests/unit/test_braille.py
--- a/tests/unit/test_braille.py
+++ b/tests/unit/test_braille.py
@@ -99,16 +99,16 @@ class TestDisplayTextForGestureIdentifier(unittest.TestCase):
 	def test_regex(self):
 		regex = braille.BrailleDisplayGesture.ID_PARTS_REGEX
 		self.assertEqual(
-			regex.search('br(noBraille.noModel):noKey1+noKey2').groups(),
-			('noBraille', '.noModel', 'noModel', 'noKey1+noKey2')
+			regex.match('br(noBraille.noModel):noKey1+noKey2').groups(),
+			('noBraille', 'noModel', 'noKey1+noKey2')
 		)
 		self.assertEqual(
-			regex.search('br(noBraille):noKey1+noKey2').groups(),
-			('noBraille', None, None, 'noKey1+noKey2')
+			regex.match('br(noBraille):noKey1+noKey2').groups(),
+			('noBraille', None, 'noKey1+noKey2')
 		)
 		# Also try a string which doesn't match the pattern
 		self.assertEqual(
-			regex.search('br[noBraille.noModel]:noKey1+noKey2'),
+			regex.match('br[noBraille.noModel]:noKey1+noKey2'),
 			None
 		)