Skip to content

Commit a55cfcf

Browse files
authored
Merge 6682c73 into 50cb4de
2 parents 50cb4de + 6682c73 commit a55cfcf

2 files changed

Lines changed: 155 additions & 123 deletions

File tree

source/bdDetect.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,12 @@ def initialize():
689689
"VID_C251&PID_1131", # Reserved
690690
"VID_C251&PID_1132", # Reserved
691691
})
692+
addUsbDevices("eurobraille", KEY_SERIAL, {
693+
"VID_28AC&PID_0012", # b.note
694+
"VID_28AC&PID_0013", # b.note 2
695+
"VID_28AC&PID_0020", # b.book internal
696+
"VID_28AC&PID_0021", # b.book external
697+
})
692698

693699
addBluetoothDevices("eurobraille", lambda m: m.id.startswith("Esys"))
694700

source/brailleDisplayDrivers/eurobraille.py

Lines changed: 149 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
#A part of NonVisual Desktop Access (NVDA)
44
#This file is covered by the GNU General Public License.
55
#See the file COPYING for more details.
6-
#Copyright (C) 2017-2019 NV Access Limited, Babbage B.V., Eurobraille
6+
#Copyright (C) 2017-2023 NV Access Limited, Babbage B.V., Eurobraille
77

88
from collections import OrderedDict, defaultdict
9-
from typing import Dict, Any, List, Union
9+
from typing import Dict, Any, List, Union, Iterator
10+
import re
1011

1112
from io import BytesIO
1213
import serial
@@ -23,6 +24,7 @@
2324
from globalCommands import SCRCAT_BRAILLE
2425
import ui
2526
import time
27+
import hwPortUtils
2628

2729
BAUD_RATE = 9600
2830

@@ -55,6 +57,7 @@
5557
EB_IRIS_TEST_sub = b'L' # 0x4c
5658
EB_VISU = b'V' # 0x56
5759
EB_VISU_DOT = b'D' # 0x44
60+
EB_CONNECTION_NAME = b'n'
5861

5962
# The eurobraille protocol uses real number characters as boolean values, so 0 (0x30) and 1 (0x31)
6063
EB_FALSE = b'0' # 0x30
@@ -65,7 +68,7 @@
6568
0x20000: "joystick1Down",
6669
0x40000: "joystick1Right",
6770
0x80000: "joystick1Left",
68-
0x100000: "joystick1Center",
71+
0x100000: "joystick1Center",
6972
0x1000000: "joystick2Up",
7073
0x2000000: "joystick2Down",
7174
0x4000000: "joystick2Right",
@@ -114,6 +117,9 @@
114117
})
115118
KEYS_ESITIME.update(KEYS_STICK)
116119

120+
KEYS_BNOTE = KEYS_ESYS
121+
KEYS_BBOOK = KEYS_ESITIME
122+
117123
DEVICE_TYPES={
118124
0x01:"Iris 20",
119125
0x02:"Iris 40",
@@ -132,8 +138,128 @@
132138
0x0f:"Esytime 32 standard",
133139
0x10:"Esytime evo 32",
134140
0x11:"Esytime evo 32 standard",
141+
0x12:"b.note",
142+
0x13:"b.note 2",
143+
0x14:"b.book",
144+
0x15:"b.book 2"
135145
}
136146

147+
defaultGestureMapEntries = {
148+
"globalCommands.GlobalCommands": {
149+
"braille_routeTo": ("br(eurobraille):routing",),
150+
"braille_reportFormatting": ("br(eurobraille):doubleRouting",),
151+
"braille_scrollBack": (
152+
"br(eurobraille.b.note):joystick1Left",
153+
"br(eurobraille):switch1Left",
154+
"br(eurobraille):l1",
155+
),
156+
"braille_scrollForward": (
157+
"br(eurobraille.b.note):joystick1Right",
158+
"br(eurobraille):switch1Right",
159+
"br(eurobraille):l8",
160+
),
161+
"braille_toFocus": (
162+
"br(eurobraille):switch1Left+switch1Right", "br(eurobraille):switch2Left+switch2Right",
163+
"br(eurobraille):switch3Left+switch3Right", "br(eurobraille):switch4Left+switch4Right",
164+
"br(eurobraille):switch5Left+switch5Right", "br(eurobraille):switch6Left+switch6Right",
165+
"br(eurobraille):l1+l8",
166+
),
167+
"review_previousLine": ("br(eurobraille):joystick1Up",),
168+
"review_nextLine": ("br(eurobraille):joystick1Down",),
169+
"review_previousCharacter": ("br(eurobraille):joystick1Left",),
170+
"review_nextCharacter": ("br(eurobraille):joystick1Right",),
171+
"reviewMode_previous": ("br(eurobraille):joystick1Left+joystick1Up",),
172+
"reviewMode_next": ("br(eurobraille):joystick1Right+joystick1Down",),
173+
# Esys and esytime have a dedicated key for backspace and combines backspace and space to perform a return.
174+
"braille_eraseLastCell": ("br(eurobraille):backSpace",),
175+
"braille_enter": ("br(eurobraille):backSpace+space",),
176+
"kb:insert": (
177+
"br(eurobraille):dot1+dot3+dot5+space",
178+
"br(eurobraille):dot3+dot4+dot5+space",
179+
),
180+
"kb:delete": ("br(eurobraille):dot3+dot6+space",),
181+
"kb:home": ("br(eurobraille):dot1+dot2+dot3+space"),
182+
"kb:end": ("br(eurobraille):dot4+dot5+dot6+space",),
183+
"kb:leftArrow": (
184+
"br(eurobraille):dot2+space",
185+
"br(eurobraille):joystick2Left",
186+
"br(eurobraille):leftArrow",
187+
),
188+
"kb:rightArrow": (
189+
"br(eurobraille):dot5+space",
190+
"br(eurobraille):joystick2Right",
191+
"br(eurobraille):rightArrow",
192+
),
193+
"kb:upArrow": (
194+
"br(eurobraille):dot4+space",
195+
"br(eurobraille):joystick2Up",
196+
"br(eurobraille):upArrow",
197+
),
198+
"kb:downArrow": (
199+
"br(eurobraille):dot6+space",
200+
"br(eurobraille):joystick2Down",
201+
"br(eurobraille):downArrow",
202+
),
203+
"kb:enter": ("br(eurobraille):joystick2Center",),
204+
"kb:pageUp": ("br(eurobraille):dot1+dot3+space",),
205+
"kb:pageDown": ("br(eurobraille):dot4+dot6+space",),
206+
"kb:numpad1": ("br(eurobraille):dot1+dot6+backspace",),
207+
"kb:numpad2": ("br(eurobraille):dot1+dot2+dot6+backspace",),
208+
"kb:numpad3": ("br(eurobraille):dot1+dot4+dot6+backspace",),
209+
"kb:numpad4": ("br(eurobraille):dot1+dot4+dot5+dot6+backspace",),
210+
"kb:numpad5": ("br(eurobraille):dot1+dot5+dot6+backspace",),
211+
"kb:numpad6": ("br(eurobraille):dot1+dot2+dot4+dot6+backspace",),
212+
"kb:numpad7": ("br(eurobraille):dot1+dot2+dot4+dot5+dot6+backspace",),
213+
"kb:numpad8": ("br(eurobraille):dot1+dot2+dot5+dot6+backspace",),
214+
"kb:numpad9": ("br(eurobraille):dot2+dot4+dot6+backspace",),
215+
"kb:numpadInsert": ("br(eurobraille):dot3+dot4+dot5+dot6+backspace",),
216+
"kb:numpadDecimal": ("br(eurobraille):dot2+backspace",),
217+
"kb:numpadDivide": ("br(eurobraille):dot3+dot4+backspace",),
218+
"kb:numpadMultiply": ("br(eurobraille):dot3+dot5+backspace",),
219+
"kb:numpadMinus": ("br(eurobraille):dot3+dot6+backspace",),
220+
"kb:numpadPlus": ("br(eurobraille):dot2+dot3+dot5+backspace",),
221+
"kb:numpadEnter": ("br(eurobraille):dot3+dot4+dot5+backspace",),
222+
"kb:escape": (
223+
"br(eurobraille):dot1+dot2+dot4+dot5+space",
224+
"br(eurobraille):l2",
225+
),
226+
"kb:tab": (
227+
"br(eurobraille):dot2+dot5+dot6+space",
228+
"br(eurobraille):l3",
229+
),
230+
"kb:shift+tab": ("br(eurobraille):dot2+dot3+dot5+space",),
231+
"kb:printScreen": ("br(eurobraille):dot1+dot3+dot4+dot6+space",),
232+
"kb:pause": ("br(eurobraille):dot1+dot4+space",),
233+
"kb:applications": ("br(eurobraille):dot5+dot6+backspace",),
234+
"kb:f1": ("br(eurobraille):dot1+backspace",),
235+
"kb:f2": ("br(eurobraille):dot1+dot2+backspace",),
236+
"kb:f3": ("br(eurobraille):dot1+dot4+backspace",),
237+
"kb:f4": ("br(eurobraille):dot1+dot4+dot5+backspace",),
238+
"kb:f5": ("br(eurobraille):dot1+dot5+backspace",),
239+
"kb:f6": ("br(eurobraille):dot1+dot2+dot4+backspace",),
240+
"kb:f7": ("br(eurobraille):dot1+dot2+dot4+dot5+backspace",),
241+
"kb:f8": ("br(eurobraille):dot1+dot2+dot5+backspace",),
242+
"kb:f9": ("br(eurobraille):dot2+dot4+backspace",),
243+
"kb:f10": ("br(eurobraille):dot2+dot4+dot5+backspace",),
244+
"kb:f11": ("br(eurobraille):dot1+dot3+backspace",),
245+
"kb:f12": ("br(eurobraille):dot1+dot2+dot3+backspace",),
246+
"kb:windows": ("br(eurobraille):dot1+dot2+dot4+dot5+dot6+space",),
247+
"kb:capsLock": ("br(eurobraille):dot7+backspace", "br(eurobraille):dot8+backspace",),
248+
"kb:numLock": ("br(eurobraille):dot3+backspace", "br(eurobraille):dot6+backspace",),
249+
"kb:shift": ("br(eurobraille):dot1+dot7+space", "br(eurobraille):dot4+dot7+space",),
250+
"braille_toggleShift": ("br(eurobraille):dot7+space","br(eurobraille):l4",),
251+
"kb:control": ("br(eurobraille):dot1+dot7+dot8+space", "br(eurobraille):dot4+dot7+dot8+space",),
252+
"braille_toggleControl": ("br(eurobraille):dot7+dot8+space","br(eurobraille):l5",),
253+
"kb:alt": ("br(eurobraille):dot1+dot8+space", "br(eurobraille):dot4+dot8+space"),
254+
"braille_toggleAlt": ("br(eurobraille):dot8+space", "br(eurobraille):l6"),
255+
"braille_toggleNVDAKey" : ("br(eurobraille):l7", "br(eurobraille):dot3+dot5+space"),
256+
"kb:control+home" : ("br(eurobraille):joystick2left+joystick2up", "br(eurobraille):l1+l2+l3", "br(eurobraille):l2+l3+l4",),
257+
"kb:control+end" : ("br(eurobraille):joystick2right+joystick2up", "br(eurobraille):l6+l7+l8", "br(eurobraille):l5+l6+l7",),
258+
"braille_toggleWindows" : ("br(eurobraille):backspace+dot1+dot2+dot3+dot4", "br(eurobraille):dot2+dot4+dot5+dot6+space",),
259+
"kb:control+shift+e" : ("br(eurobraille):dot1+dot5+space",),
260+
},
261+
}
262+
default_GestureMap = inputCore.GlobalGestureMap(defaultGestureMapEntries)
137263

138264
def bytesToInt(byteData: bytes):
139265
"""Converts bytes to its integral equivalent."""
@@ -146,7 +272,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
146272
_awaitingFrameReceipts: Dict[int, Any]
147273
name = "eurobraille"
148274
# Translators: Names of braille displays.
149-
description = _("Eurobraille Esys/Esytime/Iris displays")
275+
description = _("Eurobraille displays")
150276
isThreadSafe = True
151277
timeout = 0.2
152278
supportedSettings = (
@@ -211,6 +337,12 @@ def __init__(self, port="Auto"):
211337
# A display responded.
212338
log.info("Found {device} connected via {type} ({port})".format(
213339
device=self.deviceType, type=portType, port=port))
340+
if self.deviceType.startswith(("b.note", "b.book")):
341+
# send identifier to bnote / bbook with current COM port
342+
comportNumber = f'{int(re.match(".*?([0-9]+)$", port).group(1)):02d}'
343+
identifier = f"NVDA/{comportNumber}".encode()
344+
log.debugWarning(f"sending {identifier} to eurobraille display")
345+
self._sendPacket(EB_SYSTEM, EB_CONNECTION_NAME, identifier)
214346
break
215347
self._dev.close()
216348

@@ -222,6 +354,9 @@ def __init__(self, port="Auto"):
222354

223355
def terminate(self):
224356
try:
357+
if self.deviceType.startswith(("b.note", "b.book")):
358+
# reset identifier to bnote / bbook with current COM port
359+
self._sendPacket(EB_SYSTEM, EB_CONNECTION_NAME, b'')
225360
super(BrailleDisplayDriver, self).terminate()
226361
finally:
227362
# We must sleep before closing the port as not doing this can leave the display in a bad state where it can not be re-initialized.
@@ -313,6 +448,10 @@ def _handleSystemPacket(self, packetType: bytes, data: bytes):
313448
self.keys = KEYS_ESYS
314449
elif 0x0e <= deviceType <= 0x11: # Esitime
315450
self.keys = KEYS_ESITIME
451+
elif 0x12 <= deviceType <= 0x13:
452+
self.keys = KEYS_BNOTE
453+
elif 0x14 <= deviceType <= 0x15:
454+
self.keys = KEYS_BBOOK
316455
else:
317456
log.debugWarning("Unknown device identifier %r"%data)
318457
elif packetType == EB_SYSTEM_DISPLAY_LENGTH:
@@ -453,125 +592,11 @@ def announceUnavailableMessage():
453592
"br(eurobraille):switch1Left+joystick1Down": "toggleHidKeyboardInput",
454593
"br(eurobraille.esytime):l8+joystick1Down": "toggleHidKeyboardInput",
455594
"br(eurobraille):switch1Right+joystick1Down": "toggleHidKeyboardInput",
456-
}
457-
458-
gestureMap = inputCore.GlobalGestureMap({
459-
"globalCommands.GlobalCommands": {
460-
"braille_routeTo": ("br(eurobraille):routing",),
461-
"braille_reportFormatting": ("br(eurobraille):doubleRouting",),
462-
"braille_scrollBack": (
463-
"br(eurobraille):switch1Left",
464-
"br(eurobraille):l1",
465-
),
466-
"braille_scrollForward": (
467-
"br(eurobraille):switch1Right",
468-
"br(eurobraille):l8",
469-
),
470-
"braille_toFocus": (
471-
"br(eurobraille):switch1Left+switch1Right", "br(eurobraille):switch2Left+switch2Right",
472-
"br(eurobraille):switch3Left+switch3Right", "br(eurobraille):switch4Left+switch4Right",
473-
"br(eurobraille):switch5Left+switch5Right", "br(eurobraille):switch6Left+switch6Right",
474-
"br(eurobraille):l1+l8",
475-
),
476-
"review_previousLine": ("br(eurobraille):joystick1Up",),
477-
"review_nextLine": ("br(eurobraille):joystick1Down",),
478-
"review_previousCharacter": ("br(eurobraille):joystick1Left",),
479-
"review_nextCharacter": ("br(eurobraille):joystick1Right",),
480-
"reviewMode_previous": ("br(eurobraille):joystick1Left+joystick1Up",),
481-
"reviewMode_next": ("br(eurobraille):joystick1Right+joystick1Down",),
482-
# Esys and esytime have a dedicated key for backspace and combines backspace and space to perform a return.
483-
"braille_eraseLastCell": ("br(eurobraille):backSpace",),
484-
"braille_enter": ("br(eurobraille):backSpace+space",),
485-
"kb:insert": (
486-
"br(eurobraille):dot3+dot5+space",
487-
"br(eurobraille):l7",
488-
),
489-
"kb:delete": ("br(eurobraille):dot3+dot6+space",),
490-
"kb:home": ("br(eurobraille):dot1+dot2+dot3+space", "br(eurobraille):joystick2Left+joystick2Up",),
491-
"kb:end": ("br(eurobraille):dot4+dot5+dot6+space", "br(eurobraille):joystick2Right+joystick2Down",),
492-
"kb:leftArrow": (
493-
"br(eurobraille):dot2+space",
494-
"br(eurobraille):joystick2Left",
495-
"br(eurobraille):leftArrow",
496-
),
497-
"kb:rightArrow": (
498-
"br(eurobraille):dot5+space",
499-
"br(eurobraille):joystick2Right",
500-
"br(eurobraille):rightArrow",
501-
),
502-
"kb:upArrow": (
503-
"br(eurobraille):dot1+space",
504-
"br(eurobraille):joystick2Up",
505-
"br(eurobraille):upArrow",
506-
),
507-
"kb:downArrow": (
508-
"br(eurobraille):dot6+space",
509-
"br(eurobraille):joystick2Down",
510-
"br(eurobraille):downArrow",
511-
),
512-
"kb:enter": ("br(eurobraille):joystick2Center",),
513-
"kb:pageUp": ("br(eurobraille):dot1+dot3+space",),
514-
"kb:pageDown": ("br(eurobraille):dot4+dot6+space",),
515-
"kb:numpad1": ("br(eurobraille):dot1+dot6+backspace",),
516-
"kb:numpad2": ("br(eurobraille):dot1+dot2+dot6+backspace",),
517-
"kb:numpad3": ("br(eurobraille):dot1+dot4+dot6+backspace",),
518-
"kb:numpad4": ("br(eurobraille):dot1+dot4+dot5+dot6+backspace",),
519-
"kb:numpad5": ("br(eurobraille):dot1+dot5+dot6+backspace",),
520-
"kb:numpad6": ("br(eurobraille):dot1+dot2+dot4+dot6+backspace",),
521-
"kb:numpad7": ("br(eurobraille):dot1+dot2+dot4+dot5+dot6+backspace",),
522-
"kb:numpad8": ("br(eurobraille):dot1+dot2+dot5+dot6+backspace",),
523-
"kb:numpad9": ("br(eurobraille):dot2+dot4+dot6+backspace",),
524-
"kb:numpadInsert": ("br(eurobraille):dot3+dot4+dot5+dot6+backspace",),
525-
"kb:numpadDecimal": ("br(eurobraille):dot2+backspace",),
526-
"kb:numpadDivide": ("br(eurobraille):dot3+dot4+backspace",),
527-
"kb:numpadMultiply": ("br(eurobraille):dot3+dot5+backspace",),
528-
"kb:numpadMinus": ("br(eurobraille):dot3+dot6+backspace",),
529-
"kb:numpadPlus": ("br(eurobraille):dot2+dot3+dot5+backspace",),
530-
"kb:numpadEnter": ("br(eurobraille):dot3+dot4+dot5+backspace",),
531-
"kb:escape": (
532-
"br(eurobraille):dot1+dot2+dot4+dot5+space",
533-
"br(eurobraille):l2",
534-
),
535-
"kb:tab": (
536-
"br(eurobraille):dot2+dot5+dot6+space",
537-
"br(eurobraille):l3",
538-
),
539-
"kb:shift+tab": ("br(eurobraille):dot2+dot3+dot5+space",),
540-
"kb:printScreen": ("br(eurobraille):dot1+dot3+dot4+dot6+space",),
541-
"kb:pause": ("br(eurobraille):dot1+dot4+space",),
542-
"kb:applications": ("br(eurobraille):dot5+dot6+backspace",),
543-
"kb:f1": ("br(eurobraille):dot1+backspace",),
544-
"kb:f2": ("br(eurobraille):dot1+dot2+backspace",),
545-
"kb:f3": ("br(eurobraille):dot1+dot4+backspace",),
546-
"kb:f4": ("br(eurobraille):dot1+dot4+dot5+backspace",),
547-
"kb:f5": ("br(eurobraille):dot1+dot5+backspace",),
548-
"kb:f6": ("br(eurobraille):dot1+dot2+dot4+backspace",),
549-
"kb:f7": ("br(eurobraille):dot1+dot2+dot4+dot5+backspace",),
550-
"kb:f8": ("br(eurobraille):dot1+dot2+dot5+backspace",),
551-
"kb:f9": ("br(eurobraille):dot2+dot4+backspace",),
552-
"kb:f10": ("br(eurobraille):dot2+dot4+dot5+backspace",),
553-
"kb:f11": ("br(eurobraille):dot1+dot3+backspace",),
554-
"kb:f12": ("br(eurobraille):dot1+dot2+dot3+backspace",),
555-
"kb:windows": ("br(eurobraille):dot1+dot2+dot3+dot4+backspace",),
556-
"kb:capsLock": ("br(eurobraille):dot7+backspace", "br(eurobraille):dot8+backspace",),
557-
"kb:numLock": ("br(eurobraille):dot3+backspace", "br(eurobraille):dot6+backspace",),
558-
"kb:shift": (
559-
"br(eurobraille):dot7+space",
560-
"br(eurobraille):l4",
561-
),
562-
"braille_toggleShift": ("br(eurobraille):dot1+dot7+space", "br(eurobraille):dot4+dot7+space",),
563-
"kb:control": (
564-
"br(eurobraille):dot7+dot8+space",
565-
"br(eurobraille):l5",
566-
),
567-
"braille_toggleControl": ("br(eurobraille):dot1+dot7+dot8+space", "br(eurobraille):dot4+dot7+dot8+space",),
568-
"kb:alt": (
569-
"br(eurobraille):dot8+space",
570-
"br(eurobraille):l6",
571-
),
572-
"braille_toggleAlt": ("br(eurobraille):dot1+dot8+space", "br(eurobraille):dot4+dot8+space",),
573-
},
574-
})
595+
}\
596+
597+
gestureMap = default_GestureMap
598+
599+
575600

576601
class InputGesture(braille.BrailleDisplayGesture, brailleInput.BrailleInputGesture):
577602

@@ -581,6 +606,7 @@ def __init__(self, display):
581606
super(InputGesture, self).__init__()
582607
self.model = display.deviceType.lower().split(" ")[0]
583608
keysDown = dict(display.keysDown)
609+
584610
self.keyNames = names = []
585611
for group, groupKeysDown in keysDown.items():
586612
if group == EB_KEY_BRAILLE:

0 commit comments

Comments
 (0)