Skip to content

Commit cab267b

Browse files
authored
Merge 3b88f42 into 169c329
2 parents 169c329 + 3b88f42 commit cab267b

4 files changed

Lines changed: 276 additions & 0 deletions

File tree

108 KB
Binary file not shown.
80 KB
Binary file not shown.
23.5 KB
Binary file not shown.
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
#A part of NonVisual Desktop Access (NVDA)
2+
#This file is covered by the GNU General Public License.
3+
#See the file COPYING for more details.
4+
#Copyright (C) 2012/15 Ulf Beckmann <beckmann@flusoft.de>
5+
6+
7+
# This file represents the braille display driver for
8+
# Seika Mini, a product from Nippon Telesoft
9+
# see www.seika-braille.com for more details
10+
# 09.06.2012
11+
# Dec14/Jan15 add BrilleInput
12+
13+
from ctypes import *
14+
import time
15+
import wx
16+
import braille
17+
import brailleInput
18+
import inputCore
19+
import hwPortUtils
20+
import winUser
21+
import os
22+
from logHandler import log
23+
24+
READ_INTERVAL = 50
25+
26+
DOT_1 = 0x1
27+
DOT_2 = 0x2
28+
DOT_3 = 0x4
29+
DOT_4 = 0x8
30+
DOT_5 = 0x10
31+
DOT_6 = 0x20
32+
DOT_7 = 0x40
33+
DOT_8 = 0x80
34+
35+
36+
_keyNames = {
37+
0x000001 : "BACKSPACE",
38+
0x000002 : "SPACE",
39+
0x000004 : "LB",
40+
0x000008 : "RB",
41+
0x000010 : "LJ_CENTER",
42+
0x000020 : "LJ_LEFT",
43+
0x000040 : "LJ_RIGHT",
44+
0x000080 : "LJ_UP",
45+
0x000100 : "LJ_DOWN",
46+
0x000200 : "RJ_CENTER",
47+
0x000400 : "RJ_LEFT",
48+
0x000800 : "RJ_RIGHT",
49+
0x001000 : "RJ_UP",
50+
0x002000 : "RJ_DOWN"
51+
}
52+
53+
_dotNames = {}
54+
for i in xrange(1,9):
55+
key = globals()["DOT_%d" % i]
56+
_dotNames[key] = "d%d" % i
57+
58+
59+
# try to load the SeikaDevice.dll
60+
# first get the path of the SeikaMini.py
61+
# get the current work directory
62+
# change to this directory
63+
# load the .dll, the SeikaDevice.dll can also load by Pathname + dllname
64+
# but not the SLABxxx.dll's
65+
# after loading, set the path back to the work path
66+
67+
BASE_PATH = os.path.dirname(__file__)
68+
DLLNAME = "SeikaDevice.dll"
69+
WORK_PATH = os.getcwd()
70+
71+
if not os.path.isfile(BASE_PATH+"\\"+DLLNAME):
72+
BASE_PATH = "brailleDisplayDrivers"
73+
os.chdir(BASE_PATH)
74+
try:
75+
seikaDll=cdll.LoadLibrary(DLLNAME)
76+
except:
77+
seikaDll=None
78+
log.info("LoadLibrary failed " + DLLNAME)
79+
os.chdir(WORK_PATH)
80+
81+
class BrailleDisplayDriver(braille.BrailleDisplayDriver):
82+
name = "seikamini"
83+
description = "Seika Mini Notetaker"
84+
85+
numCells = 0
86+
87+
@classmethod
88+
def check(cls):
89+
return bool(seikaDll)
90+
91+
def seika_errcheck(res, func, args):
92+
if res != 0:
93+
raise RuntimeError("seikamini: %s: code %d" % (func.__name__, res))
94+
return res
95+
96+
def __init__(self):
97+
super(BrailleDisplayDriver, self).__init__()
98+
pint = c_int * 1
99+
nCells = pint(0)
100+
nBut = pint(0)
101+
102+
seikaDll.BrailleOpen.restype=c_int
103+
seikaDll.BrailleOpen.argtype=(c_int,c_int)
104+
105+
seikaDll.GetBrailleDisplayInfo.restype=c_int
106+
seikaDll.GetBrailleDisplayInfo.argtype=(c_void_p,c_void_p)
107+
108+
seikaDll.UpdateBrailleDisplay.restype=c_int
109+
seikaDll.UpdateBrailleDisplay.argtype=(c_char_p,c_int)
110+
111+
seikaDll.GetBrailleKey.restype=c_int
112+
seikaDll.GetBrailleKey.argtype=(c_void_p,c_void_p)
113+
114+
seikaDll.BrailleClose.restype=c_int
115+
116+
if seikaDll.BrailleOpen(2,0): # test USB
117+
seikaDll.GetBrailleDisplayInfo(nCells,nBut)
118+
log.info("seikamini an USB-HID, Cells {c} Buttons {b}".format(c=nCells[0], b=nBut[0]))
119+
self.numCells=nCells[0]
120+
else: # search the blutooth ports
121+
for portInfo in sorted(hwPortUtils.listComPorts(onlyAvailable=True), key=lambda item: "bluetoothName" in item):
122+
port = portInfo["port"]
123+
hwID = portInfo["hardwareID"]
124+
if not hwID.startswith(r"BTHENUM"): # Bluetooth Ports
125+
continue
126+
bName = ""
127+
try:
128+
bName = portInfo["bluetoothName"]
129+
except KeyError:
130+
continue
131+
if not bName.startswith(r"TSM"): # seikamini and then the 4-Digits
132+
continue
133+
134+
try:
135+
pN = port.split("COM")[1]
136+
except IndexError:
137+
pN = "0"
138+
portNum = int(pN)
139+
log.info("seikamini test {c}, {b}".format(c=port, b=bName))
140+
141+
if seikaDll.BrailleOpen(0,portNum):
142+
seikaDll.GetBrailleDisplayInfo(nCells,nBut)
143+
log.info("seikamini via Bluetooth {p} Cells {c} Buttons {b}".format(p=port,c=nCells[0], b=nBut[0]))
144+
self.numCells=nCells[0]
145+
break
146+
else:
147+
raise RuntimeError("No MINI-SEIKA display found")
148+
self._readTimer = wx.PyTimer(self.handleResponses)
149+
self._readTimer.Start(READ_INTERVAL)
150+
151+
def terminate(self):
152+
try:
153+
super(BrailleDisplayDriver, self).terminate()
154+
self._readTimer.Stop()
155+
self._readTimer = None
156+
finally:
157+
seikaDll.BrailleClose()
158+
159+
def display(self, cells):
160+
# every transmitted line consists of the preamble SEIKA_SENDHEADER and the Cells
161+
line = "".join(chr(cell) for cell in cells)
162+
expectedLength = self.numCells
163+
line += chr(0) * (expectedLength - len(line))
164+
seikaDll.UpdateBrailleDisplay(line,self.numCells)
165+
166+
def handleResponses(self):
167+
pint = c_int * 1
168+
nKey = pint(0)
169+
nRou = pint(0)
170+
Key = 0
171+
Brl = 0
172+
Rou = 0
173+
Btn = 0
174+
keys= set()
175+
if seikaDll.GetBrailleKey(nKey,nRou):
176+
Rou = nRou[0]
177+
Btn = (nKey[0] & 0xff) << 16
178+
Brl = (nKey[0] >> 8) & 0xff
179+
Key = (nKey[0] >> 16) & 0xffff
180+
space = (nKey[0] >> 16) & 0x2
181+
log.io("Seika Brl {brl} Key {c} Buttons {b} Route {r}".format(brl=Brl, c=Key, b=Btn, r=Rou))
182+
if not (Rou or Key or Btn or Brl):
183+
pass
184+
if Rou: # Routing key is pressed
185+
186+
gesture = InputGesture(routing=Rou-1)
187+
try:
188+
inputCore.manager.executeGesture(gesture)
189+
except inputCore.NoInputGestureAction:
190+
log.debug("No Action for routing command")
191+
pass
192+
if Key: # Mini Seika has no Btn ....
193+
gesture = InputGesture(keys=Key)
194+
if Btn: # Mini Seika has no Btn ....
195+
gesture = InputGesture(keys=Btn)
196+
if Brl: # or how to handle Brailleinput?
197+
gesture = InputGesture(dots=Brl)
198+
if Key or Btn or Brl:
199+
try:
200+
inputCore.manager.executeGesture(gesture)
201+
except inputCore.NoInputGestureAction:
202+
log.debug("No Action for keys ")
203+
pass
204+
205+
206+
207+
gestureMap = inputCore.GlobalGestureMap({
208+
"globalCommands.GlobalCommands": {
209+
"braille_routeTo": ("br(seikamini):routing",),
210+
"braille_scrollBack": ("br(seikamini):LB",),
211+
"braille_scrollForward": ("br(seikamini):RB",),
212+
"braille_previousLine": ("br(seikamini):LJ_UP",),
213+
"braille_nextLine": ("br(seikamini):LJ_DOWN",),
214+
"braille_toggleTether": ("br(seikamini):LJ_CENTER",),
215+
"sayAll": ("br(seikamini):SPACE+BACKSPACE",),
216+
"showGui": ("br(seikamini):RB+LB",),
217+
"kb:tab": ("br(seikamini):LJ_RIGHT",),
218+
"kb:shift+tab": ("br(seikamini):LJ_LEFT",),
219+
"kb:upArrow": ("br(seikamini):RJ_UP",),
220+
"kb:downArrow": ("br(seikamini):RJ_DOWN",),
221+
"kb:leftArrow": ("br(seikamini):RJ_LEFT",),
222+
"kb:rightArrow": ("br(seikamini):RJ_RIGHT",),
223+
"kb:shift+upArrow": ("br(seikamini):SPACE+RJ_UP",),
224+
"kb:shift+downArrow": ("br(seikamini):SPACE+RJ_DOWN",),
225+
"kb:shift+leftArrow": ("br(seikamini):SPACE+RJ_LEFT",),
226+
"kb:shift+rightArrow": ("br(seikamini):SPACE+RJ_RIGHT",),
227+
"kb:escape": ("br(seikamini):SPACE+RJ_CENTER",),
228+
"kb:shift+upArrow": ("br(seikamini):BACKSPACE+RJ_UP",),
229+
"kb:shift+downArrow": ("br(seikamini):BACKSPACE+RJ_DOWN",),
230+
"kb:shift+leftArrow": ("br(seikamini):BACKSPACE+RJ_LEFT",),
231+
"kb:shift+rightArrow": ("br(seikamini):BACKSPACE+RJ_RIGHT",),
232+
"kb:windows": ("br(seikamini):BACKSPACE+RJ_CENTER",),
233+
"kb:space": ("br(seikamini):BACKSPACE","br(seikamini):SPACE",),
234+
"kb:backspace": ("br(seikamini):d7",),
235+
"kb:pageup": ("br(seikamini):SPACE+LJ_RIGHT",),
236+
"kb:pagedown": ("br(seikamini):SPACE+LJ_LEFT",),
237+
"kb:home": ("br(seikamini):SPACE+LJ_UP",),
238+
"kb:end": ("br(seikamini):SPACE+LJ_DOWN",),
239+
"kb:control+home": ("br(seikamini):BACKSPACE+LJ_UP",),
240+
"kb:control+end": ("br(seikamini):BACKSPACE+LJ_DOWN",),
241+
"kb:enter": ("br(seikamini):RJ_CENTER","br(seikamini):d8"),
242+
},
243+
})
244+
245+
246+
class InputGestureRouting(braille.BrailleDisplayGesture):
247+
248+
source = BrailleDisplayDriver.name
249+
def __init__(self, index):
250+
super(InputGestureRouting, self).__init__()
251+
self.id = "routing"
252+
self.routingIndex = index
253+
254+
class InputGesture(braille.BrailleDisplayGesture, brailleInput.BrailleInputGesture):
255+
source = BrailleDisplayDriver.name
256+
257+
def __init__(self, keys=None, dots=None, space=False, routing=None):
258+
super(braille.BrailleDisplayGesture, self).__init__()
259+
# see what thumb keys are pressed:
260+
names = set()
261+
if keys is not None:
262+
names.update(_keyNames[1 << i] for i in xrange(22)
263+
if (1 << i) & keys)
264+
elif dots is not None:
265+
# now the dots
266+
self.dots = dots
267+
if space:
268+
self.space = space
269+
names.add(_keyNames[0])
270+
names.update(_dotNames[1 << i] for i in xrange(8)
271+
if (1 << i) & dots)
272+
elif routing is not None:
273+
self.routingIndex = routing
274+
names.add('routing')
275+
self.id = "+".join(names)
276+
log.io("keys {keys}".format(keys=names))

0 commit comments

Comments
 (0)