#brailleDisplayDrivers/alvaBC6.py #A part of NonVisual Desktop Access (NVDA) #This file is covered by the GNU General Public License. #See the file COPYING for more details. #Copyright (C) 2009-2011 Optelec B.V. , James Teh import braille import queueHandler from logHandler import log from ctypes import * from ctypes.wintypes import * import time import config import inputCore ALVA_RELEASE_MASK = 0x8000 ALVA_2ND_CR_MASK = 0x80 ALVA_KEYS = { # Thumb keys (FRONT_GROUP) 0x71: ("t1", "t2", "t3", "t4", "t5", # Only for BC680 "t1", "t2", "t3", "t4", "t5"), # eTouch keys (ETOUCH_GROUP) 0x72: ("etouch1", "etouch2", "etouch3", "etouch4"), # Smartpad keys (PDA_GROUP) 0x73: ("sp1", "sp2", "spLeft", "spEnter", "spUp", "spDown", "spRight", "sp3", "sp4", # Only for BC680 "sp1", "sp2", "spLeft", "spEnter", "spUp", "spDown", "spRight", "sp3", "sp4") } ALVA_CR_GROUP = 0x74 ALVA_MODIFIER_GROUP = 0x75 ALVA_ASCII_GROUP = 0x76 ALVA_PKEYCALLBACK = CFUNCTYPE(BOOL, c_int, USHORT, c_void_p) #Try to load alvaw32.dll try: AlvaLib=windll[r"brailleDisplayDrivers\alvaw32.dll"] except: AlvaLib=None class BrailleDisplayDriver(braille.BrailleDisplayDriver): name = "alvaBC6" # Translators: The name of a braille display. description = _("ALVA BC640/680 series") @classmethod def check(cls): return bool(AlvaLib) def __init__(self): super(BrailleDisplayDriver,self).__init__() log.debug("ALVA BC6xx Braille init") _AlvaNumDevices=c_int(0) AlvaLib.AlvaScanDevices(byref(_AlvaNumDevices)) if _AlvaNumDevices.value==0: raise RuntimeError("No ALVA display found") log.debug("%d devices found" %_AlvaNumDevices.value) AlvaLib.AlvaOpen(0) self._alva_NumCells = 0 self._keysDown = set() self._ignoreKeyReleases = False self._keyCallbackInst = ALVA_PKEYCALLBACK(self._keyCallback) AlvaLib.AlvaSetKeyCallback(0, self._keyCallbackInst, None) def terminate(self): super(BrailleDisplayDriver, self).terminate() AlvaLib.AlvaClose(1) # Drop the ctypes function instance for the key callback, # as it is holding a reference to an instance method, which causes a reference cycle. self._keyCallbackInst = None def _get_numCells(self): if self._alva_NumCells==0: NumCells = c_int(0) AlvaLib.AlvaGetCells(0, byref(NumCells)) if NumCells.value==0: raise RuntimeError("Cannot obtain number of cells") self._alva_NumCells = NumCells.value log.info("ALVA BC6xx has %d cells" %self._alva_NumCells) return self._alva_NumCells def display(self, cells): cells="".join([chr(x) for x in cells]) AlvaLib.AlvaSendBraille(0, cells, 0, len(cells)) def _keyCallback(self, dev, key, userData): group = (key >> 8) & 0x7F number = key & 0xFF if key & ALVA_RELEASE_MASK: # Release. if not self._ignoreKeyReleases and self._keysDown: try: inputCore.manager.executeGesture(InputGesture(self._keysDown)) except inputCore.NoInputGestureAction: pass # Any further releases are just the rest of the keys in the combination being released, # so they should be ignored. self._ignoreKeyReleases = True self._keysDown.discard((group, number)) else: # Press. if group == ALVA_CR_GROUP: # Execute routing keys when pressed instead of released. try: inputCore.manager.executeGesture(InputGesture(((group, number),))) except inputCore.NoInputGestureAction: pass else: self._keysDown.add((group, number)) # This begins a new key combination. self._ignoreKeyReleases = False return False gestureMap = inputCore.GlobalGestureMap({ "globalCommands.GlobalCommands": { "braille_scrollBack": ("br(alvaBC6):t1","br(alvaBC6):etouch1"), "braille_previousLine": ("br(alvaBC6):t2",), "braille_toFocus": ("br(alvaBC6):t3",), "braille_nextLine": ("br(alvaBC6):t4",), "braille_scrollForward": ("br(alvaBC6):t5","br(alvaBC6):etouch3"), "braille_routeTo": ("br(alvaBC6):routing",), "review_top": ("br(alvaBC6):t1+t2",), "review_bottom": ("br(alvaBC6):t4+t5",), "braille_toggleTether": ("br(alvaBC6):t1+t3",), "braille_cycleCursorShape": ("br(alvaBC6):t1+t4",), "braille_toggleShowCursor": ("br(alvaBC6):t2+t5",), "title": ("br(alvaBC6):etouch2",), "reportStatusLine": ("br(alvaBC6):etouch4",), "kb:shift+tab": ("br(alvaBC6):sp1",), "kb:alt": ("br(alvaBC6):sp2",), "kb:escape": ("br(alvaBC6):sp3",), "kb:tab": ("br(alvaBC6):sp4",), "kb:upArrow": ("br(alvaBC6):spUp",), "kb:downArrow": ("br(alvaBC6):spDown",), "kb:leftArrow": ("br(alvaBC6):spLeft",), "kb:rightArrow": ("br(alvaBC6):spRight",), "kb:enter": ("br(alvaBC6):spEnter",), "dateTime": ("br(alvaBC6):sp1+sp2",), "showGui": ("br(alvaBC6):sp1+sp3",), "kb:windows+d": ("br(alvaBC6):sp1+sp4",), "kb:windows+b": ("br(alvaBC6):sp3+sp4",), "kb:windows": ("br(alvaBC6):sp2+sp3",), "kb:alt+tab": ("br(alvaBC6):sp2+sp4",), "kb:control+home": ("br(alvaBC6):t3+spUp",), "kb:control+end": ("br(alvaBC6):t3+spDown",), "kb:home": ("br(alvaBC6):t3+spLeft",), "kb:end": ("br(alvaBC6):t3+spRight",), } }) class InputGesture(braille.BrailleDisplayGesture): source = BrailleDisplayDriver.name def __init__(self, keys): super(InputGesture, self).__init__() self.keyCodes = set(keys) self.keyNames = names = set() for group, number in self.keyCodes: if group == ALVA_CR_GROUP: if number & ALVA_2ND_CR_MASK: names.add("routing2") self.routingIndex = number & ~ALVA_2ND_CR_MASK else: names.add("routing") self.routingIndex = number else: try: names.add(ALVA_KEYS[group][number]) except (KeyError, IndexError): log.debugWarning("Unknown key with group %d and number %d" % (group, number)) self.id = "+".join(names)