Skip to content

Commit 1f6ce51

Browse files
authored
Merge cd3ba11 into e8cde2c
2 parents e8cde2c + cd3ba11 commit 1f6ce51

4 files changed

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

0 commit comments

Comments
 (0)