Skip to content

Commit f0f1e23

Browse files
committed
English punctuation and Indian spelling clarification
- Adding several gestures to ensure spelling clarification works for Hear2Read - Reverting all voices to have "en", English, as their language
1 parent cb5af77 commit f0f1e23

File tree

3 files changed

+249
-5
lines changed

3 files changed

+249
-5
lines changed

globalPlugins/hear2readng_global_plugin/__init__.py

Lines changed: 246 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,26 @@
1313
from threading import Thread
1414
from urllib import request
1515

16+
import api
17+
import braille
18+
import controlTypes
1619
import core
20+
import globalCommands
1721
import globalPluginHandler
1822
import gui
23+
import inputCore
1924
import queueHandler
25+
import scriptHandler
26+
import speech
27+
import textInfos
28+
import treeInterceptorHandler
29+
import ui
2030
import wx
2131
from gui.message import DisplayableError
2232
from logHandler import log
33+
from scriptHandler import script
2334
from synthDriverHandler import findAndSetNextSynth, getSynth, synthChanged
35+
from utils.security import objectBelowLockScreenAndWindowsIsLocked
2436

2537
from globalPlugins.hear2readng_global_plugin.english_settings import (
2638
EnglishSpeechSettingsDialog,
@@ -32,12 +44,16 @@
3244
from globalPlugins.hear2readng_global_plugin.voice_manager import (
3345
Hear2ReadNGVoiceManagerDialog,
3446
)
47+
from synthDrivers._H2R_NG_Speak import getCurrentVoice
3548

3649
# from .voice_manager import Hear2ReadNGVoiceManagerDialog
50+
SCRCAT_TEXTREVIEW = _("Text review")
3751

52+
curr_synth_name = ""
3853

3954
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
4055
def __init__(self, *args, **kwargs):
56+
global curr_synth_name
4157
super().__init__(*args, **kwargs)
4258
self.__voice_manager_shown = False
4359
curr_synth_name = getSynth().name
@@ -70,9 +86,11 @@ def __init__(self, *args, **kwargs):
7086
self.eng_settings_active = True
7187

7288
synthChanged.register(self.on_synth_changed)
73-
89+
7490
def on_synth_changed(self, synth):
75-
if "Hear2Read NG" in synth.name:
91+
global curr_synth_name
92+
curr_synth_name = synth.name
93+
if "Hear2Read NG" in curr_synth_name:
7694
# self.eng_settings_id = wx.Window.NewControlId()
7795
self.make_eng_settings_menu()
7896
self.eng_settings_active = True
@@ -219,3 +237,229 @@ def terminate(self):
219237
gui.mainFrame.sysTrayIcon.menu.DestroyItem(self.itemHandle)
220238
except:
221239
pass
240+
241+
242+
############################################################################
243+
# Scripts to enable spelling clarification
244+
# These scripts override native NVDA gestures, and care has been taken that
245+
# the fuctionality isn't affected outside of the Hear2Read addon and TTS
246+
############################################################################
247+
248+
@script(
249+
description=_(
250+
# Translators: Input help mode message for report current character under review cursor command.
251+
"Reports the character of the current navigator object where the review cursor is situated. "
252+
"Pressing twice reports a description or example of that character. "
253+
"Pressing three times reports the numeric value of the character in decimal and hexadecimal",
254+
),
255+
category=globalCommands.SCRCAT_TEXTREVIEW,
256+
gestures=("kb:numpad2", "kb(laptop):NVDA+."),
257+
speakOnDemand=True,
258+
)
259+
def script_h2r_review_currentCharacter(self, gesture: inputCore.InputGesture):
260+
261+
if "Hear2Read NG" not in curr_synth_name:
262+
globalCommands.commands.script_review_currentCharacter(gesture)
263+
return
264+
265+
info = api.getReviewPosition().copy()
266+
# This script is available on the lock screen via getSafeScripts, as such
267+
# ensure the review position does not contain secure information
268+
# before announcing this object
269+
if objectBelowLockScreenAndWindowsIsLocked(info.obj):
270+
ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage)
271+
return
272+
273+
info.expand(textInfos.UNIT_CHARACTER)
274+
scriptCount = scriptHandler.getLastScriptRepeatCount()
275+
log.info(f"script_review_currentCharacter interrupt: {scriptCount}, info: {info.text}")
276+
277+
if scriptCount == 1:
278+
try:
279+
lang = getCurrentVoice().split("-")[0]
280+
# Explicitly tether here
281+
braille.handler.handleReviewMove(shouldAutoTether=True)
282+
speech.speakSpelling(info.text, locale=lang, useCharacterDescriptions=True)
283+
except:
284+
globalCommands.commands.script_review_currentCharacter(gesture)
285+
else:
286+
globalCommands.commands.script_review_currentCharacter(gesture)
287+
288+
289+
@script(
290+
description=_(
291+
# Translators: Input help mode message for report current word under review cursor command.
292+
"Speaks the word of the current navigator object where the review cursor is situated. "
293+
"Pressing twice spells the word. "
294+
"Pressing three times spells the word using character descriptions",
295+
),
296+
category=globalCommands.SCRCAT_TEXTREVIEW,
297+
gestures=("kb:numpad5", "kb(laptop):NVDA+control+.", "ts(text):hoverUp"),
298+
speakOnDemand=True,
299+
)
300+
def script_h2r_review_currentWord(self, gesture: inputCore.InputGesture):
301+
302+
if "Hear2Read NG" not in curr_synth_name:
303+
globalCommands.commands.script_review_currentWord(gesture)
304+
return
305+
306+
info = api.getReviewPosition().copy()
307+
# This script is available on the lock screen via getSafeScripts, as such
308+
# ensure the review position does not contain secure information
309+
# before announcing this object
310+
if objectBelowLockScreenAndWindowsIsLocked(info.obj):
311+
ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage)
312+
return
313+
314+
info.expand(textInfos.UNIT_WORD)
315+
# Explicitly tether here
316+
braille.handler.handleReviewMove(shouldAutoTether=True)
317+
scriptCount = scriptHandler.getLastScriptRepeatCount()
318+
if scriptCount == 0:
319+
speech.speakTextInfo(info, reason=controlTypes.OutputReason.CARET, unit=textInfos.UNIT_WORD)
320+
elif scriptCount == 1:
321+
speech.spellTextInfo(info, useCharacterDescriptions=False)
322+
else:
323+
try:
324+
lang = getCurrentVoice().split("-")[0]
325+
speech.speakSpelling(info.text, locale=lang, useCharacterDescriptions=True)
326+
except:
327+
speech.speakSpelling(info.text, useCharacterDescriptions=True)
328+
329+
@script(
330+
description=_(
331+
# Translators: Input help mode message for read current line under review cursor command.
332+
"Reports the line of the current navigator object where the review cursor is situated. "
333+
"If this key is pressed twice, the current line will be spelled. "
334+
"Pressing three times will spell the line using character descriptions.",
335+
),
336+
category=globalCommands.SCRCAT_TEXTREVIEW,
337+
gestures=("kb:numpad8", "kb(laptop):NVDA+shift+."),
338+
speakOnDemand=True,
339+
)
340+
def script_h2r_review_currentLine(self, gesture: inputCore.InputGesture):
341+
342+
if "Hear2Read NG" not in curr_synth_name:
343+
globalCommands.commands.script_review_currentLine(gesture)
344+
return
345+
346+
info = api.getReviewPosition().copy()
347+
# This script is available on the lock screen via getSafeScripts, as such
348+
# ensure the review position does not contain secure information
349+
# before announcing this object
350+
if objectBelowLockScreenAndWindowsIsLocked(info.obj):
351+
ui.reviewMessage(gui.blockAction.Context.WINDOWS_LOCKED.translatedMessage)
352+
return
353+
info.expand(textInfos.UNIT_LINE)
354+
# Explicitly tether here
355+
braille.handler.handleReviewMove(shouldAutoTether=True)
356+
scriptCount = scriptHandler.getLastScriptRepeatCount()
357+
if scriptCount == 0:
358+
speech.speakTextInfo(info, unit=textInfos.UNIT_LINE, reason=controlTypes.OutputReason.CARET)
359+
elif scriptCount == 1:
360+
speech.spellTextInfo(info, useCharacterDescriptions=False)
361+
else:
362+
try:
363+
lang = getCurrentVoice().split("-")[0]
364+
speech.speakSpelling(info.text, locale=lang, useCharacterDescriptions=True)
365+
except:
366+
speech.speakSpelling(info.text, useCharacterDescriptions=True)
367+
368+
@script(
369+
description=_(
370+
# Translators: Input help mode message for report current line command.
371+
"Reports the current line under the application cursor. "
372+
"Pressing this key twice will spell the current line. "
373+
"Pressing three times will spell the line using character descriptions.",
374+
),
375+
category=globalCommands.SCRCAT_SYSTEMCARET,
376+
gestures=("kb(desktop):NVDA+upArrow", "kb(laptop):NVDA+l"),
377+
speakOnDemand=True,
378+
)
379+
def script_h2r_reportCurrentLine(self, gesture):
380+
if "Hear2Read NG" not in curr_synth_name:
381+
globalCommands.commands.script_reportCurrentLine(gesture)
382+
return
383+
384+
obj = api.getFocusObject()
385+
treeInterceptor = obj.treeInterceptor
386+
if (
387+
isinstance(treeInterceptor, treeInterceptorHandler.DocumentTreeInterceptor)
388+
and not treeInterceptor.passThrough
389+
):
390+
obj = treeInterceptor
391+
try:
392+
info = obj.makeTextInfo(textInfos.POSITION_CARET)
393+
except (NotImplementedError, RuntimeError):
394+
info = obj.makeTextInfo(textInfos.POSITION_FIRST)
395+
info.expand(textInfos.UNIT_LINE)
396+
scriptCount = scriptHandler.getLastScriptRepeatCount()
397+
if scriptCount == 0:
398+
speech.speakTextInfo(info, unit=textInfos.UNIT_LINE, reason=controlTypes.OutputReason.CARET)
399+
elif scriptCount == 1:
400+
speech.spellTextInfo(info, useCharacterDescriptions=False)
401+
else:
402+
try:
403+
lang = getCurrentVoice().split("-")[0]
404+
speech.speakSpelling(info.text, locale=lang, useCharacterDescriptions=True)
405+
except:
406+
speech.speakSpelling(info.text, useCharacterDescriptions=True)
407+
408+
@script(
409+
description=_(
410+
# Translators: Input help mode message for report current selection command.
411+
"Announces the current selection in edit controls and documents. "
412+
"Pressing twice spells this information. "
413+
"Pressing three times spells it using character descriptions. "
414+
"Pressing four times shows it in a browsable message. ",
415+
),
416+
category=globalCommands.SCRCAT_SYSTEMCARET,
417+
gestures=("kb(desktop):NVDA+shift+upArrow", "kb(laptop):NVDA+shift+s"),
418+
speakOnDemand=True,
419+
)
420+
def script_h2r_reportCurrentSelection(self, gesture):
421+
if "Hear2Read NG" not in curr_synth_name:
422+
globalCommands.commands.script_reportCurrentSelection(gesture)
423+
return
424+
425+
obj = api.getFocusObject()
426+
treeInterceptor = obj.treeInterceptor
427+
if (
428+
isinstance(treeInterceptor, treeInterceptorHandler.DocumentTreeInterceptor)
429+
and not treeInterceptor.passThrough
430+
):
431+
obj = treeInterceptor
432+
try:
433+
info = obj.makeTextInfo(textInfos.POSITION_SELECTION)
434+
except (RuntimeError, NotImplementedError):
435+
info = None
436+
if not info or info.isCollapsed:
437+
# Translators: The message reported when there is no selection
438+
ui.message(_("No selection"))
439+
else:
440+
scriptCount = scriptHandler.getLastScriptRepeatCount()
441+
# Translators: The message reported after selected text
442+
selectMessage = speech.speech._getSelectionMessageSpeech(_("%s selected"), info.text)[0]
443+
if scriptCount == 0:
444+
speech.speakTextSelected(info.text)
445+
braille.handler.message(selectMessage)
446+
elif scriptCount == 3:
447+
ui.browseableMessage(info.text, copyButton=True, closeButton=True)
448+
return
449+
450+
elif len(info.text) < speech.speech.MAX_LENGTH_FOR_SELECTION_REPORTING:
451+
if scriptCount == 1:
452+
speech.speakSpelling(info.text, useCharacterDescriptions=False)
453+
else:
454+
try:
455+
lang = getCurrentVoice().split("-")[0]
456+
speech.speakSpelling(info.text, locale=lang, useCharacterDescriptions=True)
457+
except:
458+
speech.speakSpelling(info.text, useCharacterDescriptions=True)
459+
else:
460+
speech.speakTextSelected(info.text)
461+
braille.handler.message(selectMessage)
462+
463+
############################################################################
464+
# end of scripts section
465+
############################################################################

manifest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Hear2Read NG"
22
summary = "Hear2Read Indic Speech Synthesizer"
3-
version = "1.7.0"
3+
version = "1.7.1"
44
description = "This is a speech synthesizer for 11 Indic languages and English (with Indian accent) that generates natural human speech. It is based on the work done by the piper TTS team (https://github.com/rhasspy/piper). The addon includes a voice manager for installing one or more Indic voices. Supported languages: Assamese, Bengali, Gujarati, Hindi, Kannada, Malayalam, Nepali, Odia, Punjabi, Tamil, Telugu"
55
author = "Hear2Read Contributers<info@Hear2Read.org>"
66
url = "https://hear2read.org"

synthDrivers/Hear2Read NG.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ def _processText(self, text):
193193
})
194194

195195
def _get_language(self):
196-
lang = _H2R_NG_Speak.getCurrentVoice().split("-")[0].split("_")[0]
197-
# lang = "en"
196+
# lang = _H2R_NG_Speak.getCurrentVoice().split("-")[0].split("_")[0]
197+
lang = "en"
198198
return lang
199199

200200
def speak(self, speechSequence: SpeechSequence):

0 commit comments

Comments
 (0)