Skip to content

Commit e9616fe

Browse files
authored
Merge 2ed2611 into e8cde2c
2 parents e8cde2c + 2ed2611 commit e9616fe

4 files changed

Lines changed: 285 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: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
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+
83+
class BrailleDisplayDriver(braille.BrailleDisplayDriver):
84+
name = "seikamini"
85+
description = "Seika Notetaker"
86+
87+
numCells = 0
88+
# numBtns = 0
89+
90+
@classmethod
91+
def check(cls):
92+
return bool(seikaDll)
93+
94+
def seika_errcheck(res, func, args):
95+
if res != 0:
96+
raise RuntimeError("seikamini: %s: code %d" % (func.__name__, res))
97+
return res
98+
99+
def __init__(self):
100+
super(BrailleDisplayDriver, self).__init__()
101+
pint = c_int * 1
102+
nCells = pint(0)
103+
nBut = pint(0)
104+
pN = ""
105+
106+
# seikaDll.BrailleOpen.errcheck=self.seika_errcheck
107+
seikaDll.BrailleOpen.restype = c_int
108+
seikaDll.BrailleOpen.argtype = (c_int, c_int)
109+
110+
# seikaDll.GetBrailleDisplayInfo.errcheck=self.seika_errcheck
111+
seikaDll.GetBrailleDisplayInfo.restype = c_int
112+
seikaDll.GetBrailleDisplayInfo.argtype = (c_void_p, c_void_p)
113+
114+
# seikaDll.UpdateBrailleDisplay.errcheck=self.seika_errcheck
115+
seikaDll.UpdateBrailleDisplay.restype = c_int
116+
seikaDll.UpdateBrailleDisplay.argtype = (POINTER(c_ubyte), c_int)
117+
118+
# seikaDll.GetBrailleKey.errcheck=self.seika_errcheck
119+
seikaDll.GetBrailleKey.restype = c_int
120+
seikaDll.GetBrailleKey.argtype = (c_void_p, c_void_p)
121+
122+
seikaDll.BrailleClose.restype = c_int
123+
124+
if seikaDll.BrailleOpen(2,0): # test USB
125+
seikaDll.GetBrailleDisplayInfo(nCells, nBut)
126+
log.info("seikamini an USB-HID, Cells {c} Buttons {b}".format(c=nCells[0], b=nBut[0]))
127+
self.numCells = nCells[0]
128+
#
129+
else: # search the blutooth ports
130+
for portInfo in sorted(hwPortUtils.listComPorts(onlyAvailable=True), key=lambda item: "bluetoothName" in item):
131+
port = portInfo["port"]
132+
hwID = portInfo["hardwareID"]
133+
if not hwID.startswith(r"BTHENUM"): # Bluetooth Ports
134+
continue
135+
bName = ""
136+
try:
137+
bName = portInfo["bluetoothName"]
138+
except KeyError:
139+
continue
140+
if not bName.startswith(r"TSM"): # seikamini and then the 4-Digits
141+
continue
142+
143+
try:
144+
pN = port.split("COM")[1]
145+
except IndexError:
146+
pN = "0"
147+
portNum = int(pN, 10)
148+
log.info("seikamini test {c}, {b}".format(c=port, b=bName))
149+
if seikaDll.BrailleOpen(0, portNum):
150+
seikaDll.GetBrailleDisplayInfo(nCells, nBut)
151+
log.info("seikamini via Bluetooth {p} Cells {c} Buttons {b}".format(p=port, c=nCells[0], b=nBut[0]))
152+
self.numCells = nCells[0]
153+
# self.numBtns=nBut[0]
154+
break
155+
else:
156+
raise RuntimeError("No MINI-SEIKA display found")
157+
self._readTimer = wx.PyTimer(self.handleResponses)
158+
self._readTimer.Start(READ_INTERVAL)
159+
160+
def terminate(self):
161+
try:
162+
super(BrailleDisplayDriver, self).terminate()
163+
self._readTimer.Stop()
164+
self._readTimer = None
165+
finally:
166+
seikaDll.BrailleClose()
167+
168+
def display(self, cells: List[int]):
169+
# cells will already be padded up to numCells.
170+
cellBytes = bytes(cells)
171+
seikaDll.UpdateBrailleDisplay(cellBytes,self.numCells)
172+
173+
def handleResponses(self):
174+
pint = c_int * 1
175+
nKey = pint(0)
176+
nRou = pint(0)
177+
Key = 0
178+
Brl = 0
179+
Rou = 0
180+
Btn = 0
181+
keys = set()
182+
if seikaDll.GetBrailleKey(nKey,nRou):
183+
Rou = nRou[0]
184+
Btn = (nKey[0] & 0xff) << 16
185+
Brl = (nKey[0] >> 8) & 0xff
186+
Key = (nKey[0] >> 16) & 0xffff
187+
space = (nKey[0] >> 16) & 0x2
188+
log.info("GBK Key{c}-Brl{a}-Routing{b}".format(c=Key, b=Rou, a=Brl))
189+
# log.info("Seika Brl {brl} Key {c} Buttons {b} Route {r}".format(brl=Brl, c=Key, b=Btn, r=Rou))
190+
if not (Rou or Key or Btn or Brl):
191+
pass
192+
if Rou: # Routing key is pressed
193+
gesture = InputGestureRouting(Rou-1)
194+
try:
195+
inputCore.manager.executeGesture(gesture)
196+
except inputCore.NoInputGestureAction:
197+
log.debug("No Action for routing command")
198+
pass
199+
200+
if Key: # Mini Seika has 2 Top and 4 Front ....
201+
gesture = InputGesture(keys = Key)
202+
if Btn: # Mini Seika has no Btn ....
203+
gesture = InputGesture(keys = Btn)
204+
if Brl: # or how to handle Brailleinput?
205+
gesture = InputGesture(dots = Brl)
206+
if Key or Btn or Brl:
207+
try:
208+
inputCore.manager.executeGesture(gesture)
209+
except inputCore.NoInputGestureAction:
210+
log.debug("No Action for keys ")
211+
pass
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+
257+
def __init__(self, index):
258+
super(InputGestureRouting, self).__init__()
259+
self.id = "routing"
260+
self.routingIndex = index
261+
262+
263+
class InputGesture(braille.BrailleDisplayGesture, brailleInput.BrailleInputGesture):
264+
source = BrailleDisplayDriver.name
265+
266+
def __init__(self, keys = None, dots = None, space = False, routing = None):
267+
super(braille.BrailleDisplayGesture, self).__init__()
268+
# see what thumb keys are pressed:
269+
names = set()
270+
if keys is not None:
271+
names.update(_keyNames[1 << i] for i in range(22)
272+
if (1 << i) & keys)
273+
elif dots is not None:
274+
# now the dots
275+
self.dots = dots
276+
if space:
277+
self.space = space
278+
names.add(_keyNames[0])
279+
names.update(_dotNames[1 << i] for i in range(8)
280+
if (1 << i) & dots)
281+
elif routing is not None:
282+
self.routingIndex = routing
283+
names.add('routing')
284+
self.id = "+".join(names)
285+
# log.info("keys {keys}".format(keys=names))

0 commit comments

Comments
 (0)