Date
1 - 11 of 11
Customize say all
Alberto Buffolino
Hi all,
I'm playing with say all customization, for a new add-on, as usual.
As far I know, no add-on has customized it until now, at least in this way, so I'm flying blind...
I would want to get a slightly different speech output. I initially tried to change SayAllHandler._getTextInfoSpeech behavior, invoking the original speech function and modifying its output; it worked, but this is not so good due to presence of things like "link", "quote block end" and so on.
Writing a new getTextInfoSpeech from scratch is crazy (and fragile), so I decided to act directly on text returning of TextInfo object. I created new classes to override SayAllHandler.readText (where TextReader is invoked) and TextReader.__init__ (where TextInfo object is created). See:
***
# -*- coding: UTF-8 -*-
from speech import sayAll
from logHandler import log
import weakref
import speech
import textInfos
from speech.speechWithoutPauses import SpeechWithoutPauses
partialObj = None
# to invoke externally from a script,
# before SayPartialHandler.readText
def setPartialObj(obj):
global partialObj
partialObj = obj
class _SayPartialHandler(sayAll._SayAllHandler):
def readText(self, cursor):
self.lastSayAllMode = cursor
try:
reader = _PartialTextReader(self, cursor)
except NotImplementedError:
log.debugWarning("Unable to make partial reader", exc_info=True)
return
self._getActiveSayAll = weakref.ref(reader)
reader.nextLine()
SayPartialHandler = _SayPartialHandler(
SpeechWithoutPauses(speakFunc=speech.speak),
speech.speakObject,
speech.getTextInfoSpeech,
speech.SpeakTextInfoState,
)
class _PartialTextReader(sayAll._TextReader):
def __init__(self, *args, **kwargs):
super(_PartialTextReader, self).__init__(*args, **kwargs)
# redirect to our partial text obj
self.reader = partialObj.makeTextInfo(textInfos.POSITION_CARET)
self.speakTextInfoState = SayPartialHandler._makeSpeakTextInfoState(self.reader.obj)
***
And ok, it works, but obviously nothing changed in output at this point.
My actual problem is subclassing the TextInfo object; I think I should create a class overriding _getTextRange, but the problem is: since various TextInfo implementations exist, what's the correct superclass? Trying to define it dynamically seems to be not so simple, unfortunately...
I'll appreciate any suggestions.
Alberto
I'm playing with say all customization, for a new add-on, as usual.
As far I know, no add-on has customized it until now, at least in this way, so I'm flying blind...
I would want to get a slightly different speech output. I initially tried to change SayAllHandler._getTextInfoSpeech behavior, invoking the original speech function and modifying its output; it worked, but this is not so good due to presence of things like "link", "quote block end" and so on.
Writing a new getTextInfoSpeech from scratch is crazy (and fragile), so I decided to act directly on text returning of TextInfo object. I created new classes to override SayAllHandler.readText (where TextReader is invoked) and TextReader.__init__ (where TextInfo object is created). See:
***
# -*- coding: UTF-8 -*-
from speech import sayAll
from logHandler import log
import weakref
import speech
import textInfos
from speech.speechWithoutPauses import SpeechWithoutPauses
partialObj = None
# to invoke externally from a script,
# before SayPartialHandler.readText
def setPartialObj(obj):
global partialObj
partialObj = obj
class _SayPartialHandler(sayAll._SayAllHandler):
def readText(self, cursor):
self.lastSayAllMode = cursor
try:
reader = _PartialTextReader(self, cursor)
except NotImplementedError:
log.debugWarning("Unable to make partial reader", exc_info=True)
return
self._getActiveSayAll = weakref.ref(reader)
reader.nextLine()
SayPartialHandler = _SayPartialHandler(
SpeechWithoutPauses(speakFunc=speech.speak),
speech.speakObject,
speech.getTextInfoSpeech,
speech.SpeakTextInfoState,
)
class _PartialTextReader(sayAll._TextReader):
def __init__(self, *args, **kwargs):
super(_PartialTextReader, self).__init__(*args, **kwargs)
# redirect to our partial text obj
self.reader = partialObj.makeTextInfo(textInfos.POSITION_CARET)
self.speakTextInfoState = SayPartialHandler._makeSpeakTextInfoState(self.reader.obj)
***
And ok, it works, but obviously nothing changed in output at this point.
My actual problem is subclassing the TextInfo object; I think I should create a class overriding _getTextRange, but the problem is: since various TextInfo implementations exist, what's the correct superclass? Trying to define it dynamically seems to be not so simple, unfortunately...
I'll appreciate any suggestions.
Alberto
Cyrille
Hi Alberto
No answer for you. But...
1. If you cannot find a dedicated class you may still create a class dynamically, which inherits from your initial textInfo class and from a mix-in class (derived from object), which contains only the new stuff you have implemented.
2. A more general question:
What do you plan to implement that cannot be implemented with a sayAll profile?
Cheers,
Cyrille
No answer for you. But...
1. If you cannot find a dedicated class you may still create a class dynamically, which inherits from your initial textInfo class and from a mix-in class (derived from object), which contains only the new stuff you have implemented.
2. A more general question:
What do you plan to implement that cannot be implemented with a sayAll profile?
Cheers,
Cyrille
Alberto Buffolino
Il 09/08/2022 17.15, Cyrille via groups.io ha scritto:
Hi Cyrille,
can you provide me an example?
I tried with various solutions, metaclass, type definition... but something always went wrong.
it is (would be) much more than this, but imagine to want to hear, of a text, only the words whose length is greater than 3.
Alberto
1. If you cannot find a dedicated class you may still create a class dynamically, which inherits from your initial textInfo class and from a mix-in class (derived from object), which contains only the new stuffAlberto:
Hi Cyrille,
can you provide me an example?
I tried with various solutions, metaclass, type definition... but something always went wrong.
2. A more general question:Alberto:
What do you plan to implement that cannot be implemented with a sayAll profile?
it is (would be) much more than this, but imagine to want to hear, of a text, only the words whose length is greater than 3.
Alberto
Cyrille
Ciao Alberto
I was thinking to use the "type" function to create the class. But I have not tried on your example (and do not have time to).
If you have already tested it unsuccessfully, I have no further suggestion.
I do not know if it is of some interest, but in NVDA Dev & Test Toolbox add-on,, file logReader.py, I create dynamically a class from any TreeInterceptor subclass and from a new DocumentWithLogTreeInterceptor class where I add my extra features. I do not use a generic mixin class however since all inherit from TreeInterceptor anyway. But you may have a look if it gives some ideas.
Cheers,
Cyrille
toggle quoted message
Show quoted text
I was thinking to use the "type" function to create the class. But I have not tried on your example (and do not have time to).
If you have already tested it unsuccessfully, I have no further suggestion.
I do not know if it is of some interest, but in NVDA Dev & Test Toolbox add-on,, file logReader.py, I create dynamically a class from any TreeInterceptor subclass and from a new DocumentWithLogTreeInterceptor class where I add my extra features. I do not use a generic mixin class however since all inherit from TreeInterceptor anyway. But you may have a look if it gives some ideas.
Cheers,
Cyrille
On Tue, Aug 9, 2022 at 05:43 PM, Alberto Buffolino wrote:
Il 09/08/2022 17.15, Cyrille via groups.io ha scritto:
1. If you cannot find a dedicated class you may still create a classAlberto:
dynamically, which inherits from your initial textInfo class and from a
mix-in class (derived from object), which contains only the new stuff
Hi Cyrille,
can you provide me an example?
I tried with various solutions, metaclass, type definition... but
something always went wrong.
2. A more general question:Alberto:
What do you plan to implement that cannot be implemented with a sayAll
profile?
it is (would be) much more than this, but imagine to want to hear, of a
text, only the words whose length is greater than 3.
Alberto
Abdel
Hi Cyril and all,
You wrote :
All inherit from TreeInterceptor anyway.
Disagree with this logic.
There are classes that inherit from the treeInterceptorHandler.TreeInterceptor class that add extra features.
If we stick with this logic, these extra features are not considered and we always extend the features present in the treeInterceptorHandler.TreeInterceptor class.
What are your thoughts?
Kind regards,
Abdel.
Le 09/08/2022 à 23:26, Cyrille via
groups.io a écrit :
Ciao Alberto
I was thinking to use the "type" function to create the class. But I have not tried on your example (and do not have time to).
If you have already tested it unsuccessfully, I have no further suggestion.
I do not know if it is of some interest, but in NVDA Dev & Test Toolbox add-on,, file logReader.py, I create dynamically a class from any TreeInterceptor subclass and from a new DocumentWithLogTreeInterceptor class where I add my extra features. I do not use a generic mixin class however since all inherit from TreeInterceptor anyway. But you may have a look if it gives some ideas.
Cheers,
Cyrille
On Tue, Aug 9, 2022 at 05:43 PM, Alberto Buffolino wrote:
Il 09/08/2022 17.15, Cyrille via groups.io ha scritto:
1. If you cannot find a dedicated class you may still create a classAlberto:
dynamically, which inherits from your initial textInfo class and from a
mix-in class (derived from object), which contains only the new stuff
Hi Cyrille,
can you provide me an example?
I tried with various solutions, metaclass, type definition... but
something always went wrong.
2. A more general question:Alberto:
What do you plan to implement that cannot be implemented with a sayAll
profile?
it is (would be) much more than this, but imagine to want to hear, of a
text, only the words whose length is greater than 3.
Alberto
Alberto Buffolino
Il 11/08/2022 11.02, Abdel ha scritto:
Hi Abdel,
I think it's exactly my problem, but with TextInfo.
Let it be clear that we just discuss about coding and object oriented programming, not about personal solutions if they work.
Anyway, I discovered in last days I have messed up the NVDA object and its TextInfo instance, and for the moment I partially solved operating over TextInfo instance only, and patching the _getTextRange method with a new module method, so:
***
originalFunc = None
def getPartialObj(obj):
global originalFunc
originalFunc = obj._getTextRange
obj._getTextRange = _getPartialTextRange
return obj
def _getPartialTextRange(self, *args, **kwargs):
tempText = originalFunc(self, *args, **kwargs)
log.info("TempText: %s"%tempText)
newText = ' '.join(filter(lambda i: len(i)>=4, tempText.split(" ")))
log.info("NewText: %s"%newText)
return newText
***
It works now, but only in simple text editor like notepad and notepad++. I must study a bit more the various mechanisms involved (getTextWithFields, maybe) to cover also Word and browsers, for example.
Alberto
There are classes that inherit from the treeInterceptorHandler.TreeInterceptor class that add extra features.Alberto:
If we stick with this logic, these extra features are not considered and we always extend the features present in the treeInterceptorHandler.TreeInterceptor class.
Hi Abdel,
I think it's exactly my problem, but with TextInfo.
Let it be clear that we just discuss about coding and object oriented programming, not about personal solutions if they work.
Anyway, I discovered in last days I have messed up the NVDA object and its TextInfo instance, and for the moment I partially solved operating over TextInfo instance only, and patching the _getTextRange method with a new module method, so:
***
originalFunc = None
def getPartialObj(obj):
global originalFunc
originalFunc = obj._getTextRange
obj._getTextRange = _getPartialTextRange
return obj
def _getPartialTextRange(self, *args, **kwargs):
tempText = originalFunc(self, *args, **kwargs)
log.info("TempText: %s"%tempText)
newText = ' '.join(filter(lambda i: len(i)>=4, tempText.split(" ")))
log.info("NewText: %s"%newText)
return newText
***
It works now, but only in simple text editor like notepad and notepad++. I must study a bit more the various mechanisms involved (getTextWithFields, maybe) to cover also Word and browsers, for example.
Alberto
Abdel
Hi Alberto,
Here is a global plugin for the developer's scratchpad that should do the job you're asking for.
When UIA is enabled in the settings for Word or Microsoft Edge, the method to extend for text is _getTextFromUIARange.
In other situations, it's _getTextRange.
With this example, sentences like "table of contents" should be replaced by "table contents".
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.
The module still has some imperfections, it works fine in Word when UIA is enabled, but I haven't yet added the lines to make it work when UIA is not enabled in Word only.
Otherwise, in browsers it has been tested with Microsoft Edge with UIA enabled and disabled, Google Chrome and Firefox, not tested with Internet Explorer.
It should also work in Mozilla Thunderbird, notepad and notepad++.
Sometimes lines indicating that some unreachable objects have been deleted appear in the log.
I haven't fully commented on it, but I think you should understand the different instructions well.
Hope this helps.
Kind regards,
Abdel.
toggle quoted message
Show quoted text
Here is a global plugin for the developer's scratchpad that should do the job you're asking for.
When UIA is enabled in the settings for Word or Microsoft Edge, the method to extend for text is _getTextFromUIARange.
In other situations, it's _getTextRange.
With this example, sentences like "table of contents" should be replaced by "table contents".
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.
The module still has some imperfections, it works fine in Word when UIA is enabled, but I haven't yet added the lines to make it work when UIA is not enabled in Word only.
Otherwise, in browsers it has been tested with Microsoft Edge with UIA enabled and disabled, Google Chrome and Firefox, not tested with Internet Explorer.
It should also work in Mozilla Thunderbird, notepad and notepad++.
Sometimes lines indicating that some unreachable objects have been deleted appear in the log.
I haven't fully commented on it, but I think you should understand the different instructions well.
Hope this helps.
Kind regards,
Abdel.
Le 11/08/2022 à 11:24, Alberto Buffolino a écrit :
Il 11/08/2022 11.02, Abdel ha scritto:There are classes that inherit from the treeInterceptorHandler.TreeInterceptor class that add extra features.Alberto:
If we stick with this logic, these extra features are not considered and we always extend the features present in the treeInterceptorHandler.TreeInterceptor class.
Hi Abdel,
I think it's exactly my problem, but with TextInfo.
Let it be clear that we just discuss about coding and object oriented programming, not about personal solutions if they work.
Anyway, I discovered in last days I have messed up the NVDA object and its TextInfo instance, and for the moment I partially solved operating over TextInfo instance only, and patching the _getTextRange method with a new module method, so:
***
originalFunc = None
def getPartialObj(obj):
global originalFunc
originalFunc = obj._getTextRange
obj._getTextRange = _getPartialTextRange
return obj
def _getPartialTextRange(self, *args, **kwargs):
tempText = originalFunc(self, *args, **kwargs)
log.info("TempText: %s"%tempText)
newText = ' '.join(filter(lambda i: len(i)>=4, tempText.split(" ")))
log.info("NewText: %s"%newText)
return newText
***
It works now, but only in simple text editor like notepad and notepad++. I must study a bit more the various mechanisms involved (getTextWithFields, maybe) to cover also Word and browsers, for example.
Alberto
Alberto Buffolino
Il 20/08/2022 12.17, Abdel ha scritto:
Hi Abdel,
thanks a lot for your code!
I'll study more deeply in next days, I'm quite in pause now... I have seen various interesting tricks.
Anyway, in my plans these bad things happen only when user launches the specific say all, that not override the standard one, so it'd be less risky.
Thanks again.
Alberto
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.Alberto:
Hi Abdel,
thanks a lot for your code!
I'll study more deeply in next days, I'm quite in pause now... I have seen various interesting tricks.
Anyway, in my plans these bad things happen only when user launches the specific say all, that not override the standard one, so it'd be less risky.
Thanks again.
Alberto
Abdel
Hi Alberto,
No problem, thank you for your always very instructive and enriching questions.
As you can see, I used 2 mixin classes.
The objective is to be able to call the super method while respecting the MRO order.
In a function external to the class hierarchy, super will not work.
Another thing, getTextWithFields method is used in Google Chrome and Firefox browsers when reading text in browse mode, that's why I extended its features in Mixin class.
With notepad and notepad++, extending the functionality of the _getTextRange method is enough to take text modification into account.
That's why I extended these 2 methods.
I think extending only getTextWithFields would be more than enough, you can test if you want.
Kind regards,
Abdel.
toggle quoted message
Show quoted text
No problem, thank you for your always very instructive and enriching questions.
As you can see, I used 2 mixin classes.
The objective is to be able to call the super method while respecting the MRO order.
In a function external to the class hierarchy, super will not work.
Another thing, getTextWithFields method is used in Google Chrome and Firefox browsers when reading text in browse mode, that's why I extended its features in Mixin class.
With notepad and notepad++, extending the functionality of the _getTextRange method is enough to take text modification into account.
That's why I extended these 2 methods.
I think extending only getTextWithFields would be more than enough, you can test if you want.
Kind regards,
Abdel.
Le 20/08/2022 à 16:56, Alberto Buffolino a écrit :
Il 20/08/2022 12.17, Abdel ha scritto:This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.Alberto:
Hi Abdel,
thanks a lot for your code!
I'll study more deeply in next days, I'm quite in pause now... I have seen various interesting tricks.
Anyway, in my plans these bad things happen only when user launches the specific say all, that not override the standard one, so it'd be less risky.
Thanks again.
Alberto
Travis Roth
Hi Abdel,
Did you post a link for the add-on? I am not finding it in the message?
Thanks.
toggle quoted message
Show quoted text
Did you post a link for the add-on? I am not finding it in the message?
Thanks.
-----Original Message-----
From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Abdel
Sent: Saturday, August 20, 2022 5:17 AM
To: nvda-addons@nvda-addons.groups.io
Subject: Re: [nvda-addons] Customize say all
Hi Alberto,
Here is a global plugin for the developer's scratchpad that should do the job you're asking for.
When UIA is enabled in the settings for Word or Microsoft Edge, the method to extend for text is _getTextFromUIARange.
In other situations, it's _getTextRange.
With this example, sentences like "table of contents" should be replaced by "table contents".
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.
The module still has some imperfections, it works fine in Word when UIA is enabled, but I haven't yet added the lines to make it work when UIA is not enabled in Word only.
Otherwise, in browsers it has been tested with Microsoft Edge with UIA enabled and disabled, Google Chrome and Firefox, not tested with Internet Explorer.
It should also work in Mozilla Thunderbird, notepad and notepad++.
Sometimes lines indicating that some unreachable objects have been deleted appear in the log.
I haven't fully commented on it, but I think you should understand the different instructions well.
Hope this helps.
Kind regards,
Abdel.
Le 11/08/2022 à 11:24, Alberto Buffolino a écrit :
From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Abdel
Sent: Saturday, August 20, 2022 5:17 AM
To: nvda-addons@nvda-addons.groups.io
Subject: Re: [nvda-addons] Customize say all
Hi Alberto,
Here is a global plugin for the developer's scratchpad that should do the job you're asking for.
When UIA is enabled in the settings for Word or Microsoft Edge, the method to extend for text is _getTextFromUIARange.
In other situations, it's _getTextRange.
With this example, sentences like "table of contents" should be replaced by "table contents".
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.
The module still has some imperfections, it works fine in Word when UIA is enabled, but I haven't yet added the lines to make it work when UIA is not enabled in Word only.
Otherwise, in browsers it has been tested with Microsoft Edge with UIA enabled and disabled, Google Chrome and Firefox, not tested with Internet Explorer.
It should also work in Mozilla Thunderbird, notepad and notepad++.
Sometimes lines indicating that some unreachable objects have been deleted appear in the log.
I haven't fully commented on it, but I think you should understand the different instructions well.
Hope this helps.
Kind regards,
Abdel.
Le 11/08/2022 à 11:24, Alberto Buffolino a écrit :
Il 11/08/2022 11.02, Abdel ha scritto:There are classes that inherit from theAlberto:
treeInterceptorHandler.TreeInterceptor class that add extra features.
If we stick with this logic, these extra features are not considered
and we always extend the features present in the
treeInterceptorHandler.TreeInterceptor class.
Hi Abdel,
I think it's exactly my problem, but with TextInfo.
Let it be clear that we just discuss about coding and object oriented
programming, not about personal solutions if they work.
Anyway, I discovered in last days I have messed up the NVDA object
and its TextInfo instance, and for the moment I partially solved
operating over TextInfo instance only, and patching the _getTextRange
method with a new module method, so:
***
originalFunc = None
def getPartialObj(obj):
global originalFunc
originalFunc = obj._getTextRange
obj._getTextRange = _getPartialTextRange
return obj
def _getPartialTextRange(self, *args, **kwargs):
tempText = originalFunc(self, *args, **kwargs)
log.info("TempText: %s"%tempText)
newText = ' '.join(filter(lambda i: len(i)>=4, tempText.split("
")))
log.info("NewText: %s"%newText)
return newText
***
It works now, but only in simple text editor like notepad and
notepad++. I must study a bit more the various mechanisms involved
(getTextWithFields, maybe) to cover also Word and browsers, for example.
Alberto
Abdel
Hi,
Here is the download link of the module compressed in zip:
Abdel.
Le 20/08/2022 à 19:52, Travis Roth a écrit :
Here is the download link of the module compressed in zip:
http://cyber25.free.fr/nvda-addons/customizedTextInfo.zipKind regards,
Abdel.
Le 20/08/2022 à 19:52, Travis Roth a écrit :
Hi Abdel,
Did you post a link for the add-on? I am not finding it in the message?
Thanks.
-----Original Message-----
From: nvda-addons@nvda-addons.groups.io <nvda-addons@nvda-addons.groups.io> On Behalf Of Abdel
Sent: Saturday, August 20, 2022 5:17 AM
To: nvda-addons@nvda-addons.groups.io
Subject: Re: [nvda-addons] Customize say all
Hi Alberto,
Here is a global plugin for the developer's scratchpad that should do the job you're asking for.
When UIA is enabled in the settings for Word or Microsoft Edge, the method to extend for text is _getTextFromUIARange.
In other situations, it's _getTextRange.
With this example, sentences like "table of contents" should be replaced by "table contents".
This type of practice is not highly recommended, as it changes NVDA's internal behavior when reading text.
The module still has some imperfections, it works fine in Word when UIA is enabled, but I haven't yet added the lines to make it work when UIA is not enabled in Word only.
Otherwise, in browsers it has been tested with Microsoft Edge with UIA enabled and disabled, Google Chrome and Firefox, not tested with Internet Explorer.
It should also work in Mozilla Thunderbird, notepad and notepad++.
Sometimes lines indicating that some unreachable objects have been deleted appear in the log.
I haven't fully commented on it, but I think you should understand the different instructions well.
Hope this helps.
Kind regards,
Abdel.
Le 11/08/2022 à 11:24, Alberto Buffolino a écrit :Il 11/08/2022 11.02, Abdel ha scritto:There are classes that inherit from theAlberto:
treeInterceptorHandler.TreeInterceptor class that add extra features.
If we stick with this logic, these extra features are not considered
and we always extend the features present in the
treeInterceptorHandler.TreeInterceptor class.
Hi Abdel,
I think it's exactly my problem, but with TextInfo.
Let it be clear that we just discuss about coding and object oriented
programming, not about personal solutions if they work.
Anyway, I discovered in last days I have messed up the NVDA object
and its TextInfo instance, and for the moment I partially solved
operating over TextInfo instance only, and patching the _getTextRange
method with a new module method, so:
***
originalFunc = None
def getPartialObj(obj):
global originalFunc
originalFunc = obj._getTextRange
obj._getTextRange = _getPartialTextRange
return obj
def _getPartialTextRange(self, *args, **kwargs):
tempText = originalFunc(self, *args, **kwargs)
log.info("TempText: %s"%tempText)
newText = ' '.join(filter(lambda i: len(i)>=4, tempText.split("
")))
log.info("NewText: %s"%newText)
return newText
***
It works now, but only in simple text editor like notepad and
notepad++. I must study a bit more the various mechanisms involved
(getTextWithFields, maybe) to cover also Word and browsers, for example.
Alberto