Skip to content

Commit 4bc424f

Browse files
authored
Merge e2e0e12 into e8cde2c
2 parents e8cde2c + e2e0e12 commit 4bc424f

4 files changed

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

0 commit comments

Comments
 (0)