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
88from collections import OrderedDict , defaultdict
99from typing import Dict , Any , List , Union
10+ import re
1011
1112from io import BytesIO
1213import serial
5556EB_IRIS_TEST_sub = b'L' # 0x4c
5657EB_VISU = b'V' # 0x56
5758EB_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)
6062EB_FALSE = b'0' # 0x30
6567 0x20000 : "joystick1Down" ,
6668 0x40000 : "joystick1Right" ,
6769 0x80000 : "joystick1Left" ,
68- 0x100000 : "joystick1Center" ,
70+ 0x100000 : "joystick1Center" ,
6971 0x1000000 : "joystick2Up" ,
7072 0x2000000 : "joystick2Down" ,
7173 0x4000000 : "joystick2Right" ,
114116})
115117KEYS_ESITIME .update (KEYS_STICK )
116118
119+ KEYS_BNOTE = KEYS_ESYS
120+ KEYS_BBOOK = KEYS_ESITIME
121+
117122DEVICE_TYPES = {
118123 0x01 :"Iris 20" ,
119124 0x02 :"Iris 40" ,
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
138272def 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
576608class 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