Skip to content

Commit cbdbdd5

Browse files
authored
Merge b097fee into 9958841
2 parents 9958841 + b097fee commit cbdbdd5

2 files changed

Lines changed: 163 additions & 124 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: 157 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# -*- coding: UTF-8 -*-
2-
#brailleDisplayDrivers/esys.py
3-
#A part of NonVisual Desktop Access (NVDA)
4-
#This file is covered by the GNU General Public License.
5-
#See the file COPYING for more details.
6-
#Copyright (C) 2017-2019 NV Access Limited, Babbage B.V., Eurobraille
2+
# brailleDisplayDrivers/esys.py
3+
# A part of NonVisual Desktop Access (NVDA)
4+
# This file is covered by the GNU General Public License.
5+
# See the file COPYING for more details.
6+
# Copyright (C) 2017-2023 NV Access Limited, Babbage B.V., Eurobraille
77

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

1112
from io import BytesIO
1213
import serial
@@ -55,6 +56,7 @@
5556
EB_IRIS_TEST_sub = b'L' # 0x4c
5657
EB_VISU = b'V' # 0x56
5758
EB_VISU_DOT = b'D' # 0x44
59+
EB_CONNECTION_NAME = b'n'
5860

5961
# The eurobraille protocol uses real number characters as boolean values, so 0 (0x30) and 1 (0x31)
6062
EB_FALSE = b'0' # 0x30
@@ -65,7 +67,7 @@
6567
0x20000: "joystick1Down",
6668
0x40000: "joystick1Right",
6769
0x80000: "joystick1Left",
68-
0x100000: "joystick1Center",
70+
0x100000: "joystick1Center",
6971
0x1000000: "joystick2Up",
7072
0x2000000: "joystick2Down",
7173
0x4000000: "joystick2Right",
@@ -114,6 +116,9 @@
114116
})
115117
KEYS_ESITIME.update(KEYS_STICK)
116118

119+
KEYS_BNOTE = KEYS_ESYS
120+
KEYS_BBOOK = KEYS_ESITIME
121+
117122
DEVICE_TYPES={
118123
0x01:"Iris 20",
119124
0x02:"Iris 40",
@@ -132,8 +137,137 @@
132137
0x0f:"Esytime 32 standard",
133138
0x10:"Esytime evo 32",
134139
0x11:"Esytime evo 32 standard",
140+
0x12: "b.note",
141+
0x13: "b.note 2",
142+
0x14: "b.book",
143+
0x15: "b.book 2"
135144
}
136145

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

138272
def bytesToInt(byteData: bytes):
139273
"""Converts bytes to its integral equivalent."""
@@ -146,7 +280,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
146280
_awaitingFrameReceipts: Dict[int, Any]
147281
name = "eurobraille"
148282
# Translators: Names of braille displays.
149-
description = _("Eurobraille Esys/Esytime/Iris displays")
283+
description = _("Eurobraille displays")
150284
isThreadSafe = True
151285
timeout = 0.2
152286
supportedSettings = (
@@ -211,6 +345,12 @@ def __init__(self, port="Auto"):
211345
# A display responded.
212346
log.info("Found {device} connected via {type} ({port})".format(
213347
device=self.deviceType, type=portType, port=port))
348+
if self.deviceType.startswith(("b.note", "b.book")):
349+
# send identifier to bnote / bbook with current COM port
350+
comportNumber = f'{int(re.match(".*?([0-9]+)$", port).group(1)):02d}'
351+
identifier = f"NVDA/{comportNumber}".encode()
352+
log.debugWarning(f"sending {identifier} to eurobraille display")
353+
self._sendPacket(EB_SYSTEM, EB_CONNECTION_NAME, identifier)
214354
break
215355
self._dev.close()
216356

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

223363
def terminate(self):
224364
try:
365+
if self.deviceType.startswith(("b.note", "b.book")):
366+
# reset identifier to bnote / bbook with current COM port
367+
self._sendPacket(EB_SYSTEM, EB_CONNECTION_NAME, b'')
225368
super(BrailleDisplayDriver, self).terminate()
226369
finally:
227370
# 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 +456,10 @@ def _handleSystemPacket(self, packetType: bytes, data: bytes):
313456
self.keys = KEYS_ESYS
314457
elif 0x0e <= deviceType <= 0x11: # Esitime
315458
self.keys = KEYS_ESITIME
459+
elif 0x12 <= deviceType <= 0x13:
460+
self.keys = KEYS_BNOTE
461+
elif 0x14 <= deviceType <= 0x15:
462+
self.keys = KEYS_BBOOK
316463
else:
317464
log.debugWarning("Unknown device identifier %r"%data)
318465
elif packetType == EB_SYSTEM_DISPLAY_LENGTH:
@@ -454,124 +601,9 @@ def announceUnavailableMessage():
454601
"br(eurobraille.esytime):l8+joystick1Down": "toggleHidKeyboardInput",
455602
"br(eurobraille):switch1Right+joystick1Down": "toggleHidKeyboardInput",
456603
}
604+
gestureMap = default_GestureMap
605+
457606

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-
})
575607

576608
class InputGesture(braille.BrailleDisplayGesture, brailleInput.BrailleInputGesture):
577609

@@ -581,6 +613,7 @@ def __init__(self, display):
581613
super(InputGesture, self).__init__()
582614
self.model = display.deviceType.lower().split(" ")[0]
583615
keysDown = dict(display.keysDown)
616+
584617
self.keyNames = names = []
585618
for group, groupKeysDown in keysDown.items():
586619
if group == EB_KEY_BRAILLE:

0 commit comments

Comments
 (0)