Skip to content

Commit faf6410

Browse files
committed
Changes to support new "audio" element meant for beeps for cap letters
Changed pause factor scale to be logarithmic so that 100% is in the middle Added type hints and turned on linting Fixed a few names so the linter is happy
1 parent 2f473bb commit faf6410

File tree

3 files changed

+80
-55
lines changed

3 files changed

+80
-55
lines changed

NVDA-addon/addon/globalPlugins/MathCAT/MathCAT.py

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121
import ui # copy message
2222
from scriptHandler import script # copy MathML via ctrl-c
2323
from synthDriverHandler import getSynth # speech engine param setting
24-
import winUser # clipboard manipultation
24+
import winUser # clipboard manipulation
25+
import gettext
26+
_ = gettext.gettext
2527
from ctypes import windll # register clipboard formats
28+
from typing import Any, Optional
2629

2730
from . import libmathcat
2831

@@ -48,6 +51,7 @@
4851
# Prosody.
4952
r"|<prosody(?: pitch='(?P<pitch>\d+)%')?(?: volume='(?P<volume>\d+)%')?(?: rate='(?P<rate>\d+)%')?> ?"
5053
r"|(?P<prosodyReset></prosody>) ?"
54+
r"|<audio src='(?P<beep>beep.mp4)'>.*?</audio> ?" # hack for beeps
5155
# Other tags, which we don't care about.
5256
r"|<[^>]+> ?"
5357
# Commas indicating pauses in navigation messages.
@@ -61,7 +65,7 @@
6165
"rate": RateCommand,
6266
}
6367

64-
def ConvertSSMLTextForNVDA(text, language=""):
68+
def ConvertSSMLTextForNVDA(text:str, language:str=""):
6569
# MathCAT's default rate is 180 wpm.
6670
# Assume that 0% is 80 wpm and 100% is 450 wpm and scale accordingly.
6771
synth = getSynth()
@@ -82,24 +86,20 @@ def ConvertSSMLTextForNVDA(text, language=""):
8286
if use_break:
8387
out.append(BreakCommand(time=int(int(m.group("break")) * breakMulti)))
8488
elif m.lastgroup == "char":
85-
# get the NVDA settings for what to do for a capital char and apply them
8689
ch = m.group("char")
87-
if ch.isupper():
88-
if synthConfig["sayCapForCapitals"]:
89-
out.append(_(u"cap")) # capital letter prefix
90-
if use_pitch:
91-
out.append(PitchCommand(multiplier=int(synthConfig["capPitchChange"])))
92-
if synthConfig["beepForCapitals"]:
93-
out.append(BeepCommand(2000, 50))
9490
if use_character:
9591
out.extend((CharacterModeCommand(True), ch, CharacterModeCommand(False)))
9692
else:
9793
out.extend((" ", ch, " "))
98-
if use_pitch and ch.isupper():
99-
out.append(PitchCommand(multiplier=1))
10094
elif m.lastgroup == "comma":
10195
if use_break:
10296
out.append(BreakCommand(time=100))
97+
elif m.lastgroup == "beep":
98+
out.append(BeepCommand(2000, 50))
99+
elif m.lastgroup == "pitch":
100+
if use_pitch:
101+
out.append(PitchCommand(multiplier=int(m.group(m.lastgroup))))
102+
resetProsody.add(PitchCommand)
103103
elif m.lastgroup in PROSODY_COMMANDS:
104104
command = PROSODY_COMMANDS[m.lastgroup]
105105
if command in supported_commands:
@@ -130,7 +130,7 @@ class MathCATInteraction(mathPres.MathInteractionNVDAObject):
130130
CF_MathML_Presentation = windll.user32.RegisterClipboardFormatW("MathML Presentation")
131131
# log.info("2**** MathCAT registering data formats: CF_MathML %x, CF_MathML_Presentation %x" % (CF_MathML, CF_MathML_Presentation))
132132

133-
def __init__(self, provider=None, mathMl=None):
133+
def __init__(self, provider=None, mathMl: Optional[str]=None):
134134
super(MathCATInteraction, self).__init__(provider=provider, mathMl=mathMl)
135135
provider._setSpeechLanguage(mathMl)
136136
try:
@@ -149,7 +149,7 @@ def reportFocus(self):
149149
speech.speakMessage(_("Error in speaking math: see NVDA error log for details"))
150150

151151

152-
def getBrailleRegions(self, review=False):
152+
def getBrailleRegions(self, review: bool = False):
153153
# log.info("***MathCAT start getBrailleRegions")
154154
yield braille.NVDAObjectRegion(self, appendText=" ")
155155
region = braille.Region()
@@ -165,7 +165,7 @@ def getBrailleRegions(self, review=False):
165165
# log.info("***MathCAT end getBrailleRegions ***")
166166
yield region
167167

168-
def getScript(self, gesture):
168+
def getScript(self, gesture: KeyboardInputGesture):
169169
# Pass most keys to MathCAT. Pretty ugly.
170170
if isinstance(gesture, KeyboardInputGesture) and "NVDA" not in gesture.modifierNames and (
171171
gesture.mainKeyName in {
@@ -178,7 +178,7 @@ def getScript(self, gesture):
178178
return self.script_navigate
179179
return super().getScript(gesture)
180180

181-
def script_navigate(self, gesture):
181+
def script_navigate(self, gesture: KeyboardInputGesture):
182182
# log.info("***MathCAT script_navigate")
183183
try:
184184
if gesture != None:
@@ -206,11 +206,11 @@ def script_navigate(self, gesture):
206206
@script(
207207
gesture="kb:control+c",
208208
)
209-
def script_rawdataToClip(self, gesture):
209+
def script_rawdataToClip(self, gesture: KeyboardInputGesture):
210210
try:
211211
mathml = libmathcat.GetNavigationMathML()[0]
212212
if not re.match(self._startsWithMath, mathml):
213-
mathml = "<math>" + mathml + "</math>" # copy will fix up namespacing
213+
mathml = "<math>" + mathml + "</math>" # copy will fix up name spacing
214214
self._copyToClipAsMathML(mathml)
215215
ui.message(_("copy"))
216216
except Exception as e:
@@ -227,7 +227,6 @@ def _wrapMathMLForClipBoard(self, text: str) -> str:
227227
mathml_with_ns = mathml_with_ns.replace('math', 'math xmlns="http://www.w3.org/1998/Math/MathML"', 1)
228228
return '<?xml version="1.0"?>' + mathml_with_ns
229229

230-
from typing import Any, Optional
231230
def _copyToClipAsMathML(self, text: str, notify: Optional[bool] = False) -> bool:
232231
"""Copies the given text to the windows clipboard.
233232
@returns: True if it succeeds, False otherwise.
@@ -238,8 +237,9 @@ def _copyToClipAsMathML(self, text: str, notify: Optional[bool] = False) -> bool
238237
if not isinstance(text, str) or len(text) == 0:
239238
return False
240239
from api import getClipData
240+
from mainFrame import Handle
241241
try:
242-
with winUser.openClipboard(mainFrame.Handle):
242+
with winUser.openClipboard(Handle):
243243
winUser.emptyClipboard()
244244
self._setClipboardData(self.CF_MathML, self._wrapMathMLForClipBoard(text))
245245
self._setClipboardData(self.CF_MathML_Presentation, self._wrapMathMLForClipBoard(text))
@@ -257,13 +257,13 @@ def _copyToClipAsMathML(self, text: str, notify: Optional[bool] = False) -> bool
257257
ui.reportTextCopiedToClipboard() # No argument reports a failure.
258258
return False
259259

260-
def _setClipboardData(self, format,data):
260+
def _setClipboardData(self, format, data: str):
261261
# Need to support MathML Presentation, so this copied from winUser.py and the first two lines are commented out
262262
# For now only unicode is a supported format
263263
# if format!=CF_UNICODETEXT:
264264
# raise ValueError("Unsupported format")
265265
from textUtils import WCHAR_ENCODING
266-
from ctypes import c_wchar
266+
from ctypes import c_wchar, WinError
267267
import winKernel
268268
text = data
269269
bufLen = len(text.encode(WCHAR_ENCODING, errors="surrogatepass")) + 2
@@ -276,7 +276,7 @@ def _setClipboardData(self, format,data):
276276
buf.value=text
277277
# Set the clipboard data with the global memory
278278
if not windll.user32.SetClipboardData(format,h):
279-
raise ctypes.WinError()
279+
raise WinError()
280280
# NULL the global memory handle so that it is not freed at the end of scope as the clipboard now has it.
281281
h.forget()
282282

@@ -296,7 +296,7 @@ def __init__(self):
296296
speech.speakMessage(_("MathCAT initialization failed: see NVDA error log for details"))
297297

298298

299-
def getSpeechForMathMl(self, mathml):
299+
def getSpeechForMathMl(self, mathml: str):
300300
self._setSpeechLanguage(mathml)
301301
try:
302302
libmathcat.SetMathML(mathml)
@@ -305,6 +305,14 @@ def getSpeechForMathMl(self, mathml):
305305
speech.speakMessage(_("Illegal MathML found: see NVDA error log for details"))
306306
libmathcat.SetMathML("<math></math>") # set it to something
307307
try:
308+
synth = getSynth()
309+
synthConfig = config.conf["speech"][synth.name]
310+
supported_commands = synth.supportedCommands
311+
# Set preferences for capital letters
312+
libmathcat.SetPreference("CapitalLetters_Beep", "true" if synthConfig["beepForCapitals"] else "false")
313+
libmathcat.SetPreference("CapitalLetters_UseWord", "true" if synthConfig["sayCapForCapitals"] else "false")
314+
if PitchCommand in supported_commands:
315+
libmathcat.SetPreference("CapitalLetters_Pitch", str(synthConfig["capPitchChange"]))
308316
if self._add_sounds():
309317
return [BeepCommand(800,25)] + ConvertSSMLTextForNVDA(libmathcat.GetSpokenText()) + [BeepCommand(600,15)]
310318
else:
@@ -321,7 +329,7 @@ def _add_sounds(self):
321329
except:
322330
return False
323331

324-
def getBrailleForMathMl(self, mathml):
332+
def getBrailleForMathMl(self, mathml: str):
325333
# log.info("***MathCAT getBrailleForMathMl")
326334
try:
327335
libmathcat.SetMathML(mathml)
@@ -337,18 +345,14 @@ def getBrailleForMathMl(self, mathml):
337345
return ""
338346

339347

340-
def interactWithMathMl(self, mathMl):
341-
MathCATInteraction(provider=self, mathMl=mathMl).setFocus()
342-
MathCATInteraction(provider=self, mathMl=mathMl).script_navigate(None)
348+
def interactWithMathMl(self, mathml: str):
349+
MathCATInteraction(provider=self, mathMl=mathml).setFocus()
350+
MathCATInteraction(provider=self, mathMl=mathml).script_navigate(None)
343351

344-
def _setSpeechLanguage(self, mathMl):
345-
lang = mathPres.getLanguageFromMath(mathMl)
346-
if not lang:
347-
lang = speech.getCurrentLanguage()
348-
try:
349-
libmathcat.SetPreference("Language", lang.replace("_", "-"))
350-
self._language = lang
351-
except Exception as e:
352-
log.error(e)
353-
speech.speakMessage(_("MathCAT does not support language %s: see NVDA error log for details" % lang))
352+
def _setSpeechLanguage(self, mathml: str):
353+
# NVDA inserts its notion of the current language into the math tag, so we can't use it
354+
# see nvda\source\mathPres\mathPlayer.py for original version of this code
355+
# lang = mathPres.getLanguageFromMath(mathml)
354356

357+
# it might have changed, so can't just set it in init()
358+
self._language = libmathcat.GetPreference("Language")

0 commit comments

Comments
 (0)