Page 5 of 6

Re: Display label count

Posted: Tue Oct 28, 2014 10:07 pm
by Robert J. H.
Hi Edgar, thanks for taking the time.

Your guesses are very close to the truth.
(NVDA uses Python as script language, JAWS has a proprietary script language that is similar)
I can get the object with focus very simple (from a script or the python console):

Code: Select all

FocusObject = api.getFocusObject()
and from there you can simply type

Code: Select all

focusObject.windowClassName
to get e.g. u'Edit' for an edit field.
The predefined methods and attributes can be got with dir(obj):

Code: Select all

>>> dir(focus)
['APIClass', 'IA2Attributes', 'IA2UniqueID', 'IAccessibleChildID', 'IAccessibleIdentity', 'IAccessibleObject', 'IAccessibleRole', 'IAccessibleStates', 'IAccessibleTableUsesTableCellIndexAttrib', 'IID_ITextServices', 'SLEEP_FULL', 'TextInfo', '_AutoPropertyObject__instances', '_IA2Relations', '_IATableCell', '_IAccessibleIdentity', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_appModuleRef', '_cache_role', '_cache_sleepMode', '_findSimpleNext', '_formatLongDevInfoString', '_gestureMap', '_getIA2RelationFirstTarget', '_getPropertyViaCache', '_get_IA2Attributes', '_get_IAccessibleIdentity', '_get_IAccessibleRole', '_get_IAccessibleStates', '_get_TextInfo', '_get__IA2Relations', '_get__IATableCell', '_get_actionCount', '_get_activeChild', '_get_allowIAccessibleChildIDAndChildCountForPositionInfo', '_get_appModule', '_get_basicText', '_get_cellCoordsText', '_get_childCount', '_get_children', '_get_columnCount', '_get_columnHeaderText', '_get_columnNumber', '_get_container', '_get_decodedAccDescription', '_get_defaultActionIndex', '_get_description', '_get_devInfo', '_get_displayText', '_get_embeddingTextInfo', '_get_firstChild', '_get_flatReviewPosition', '_get_flowsFrom', '_get_flowsTo', '_get_groupName', '_get_hasFocus', '_get_indexInParent', '_get_isFocusable', '_get_isInForeground', '_get_isPresentableFocusAncestor', '_get_isProtected', '_get_isWindowUnicode', '_get_keyboardShortcut', '_get_labeledBy', '_get_lastChild', '_get_location', '_get_locationText', '_get_name', '_get_next', '_get_parent', '_get_positionInfo', '_get_presentationType', '_get_previous', '_get_processHandle', '_get_processID', '_get_recursiveDescendants', '_get_role', '_get_rowCount', '_get_rowHeaderText', '_get_rowNumber', '_get_shouldAllowIAccessibleFocusEvent', '_get_simpleFirstChild', '_get_simpleLastChild', '_get_simpleNext', '_get_simpleParent', '_get_simplePrevious', '_get_sleepMode', '_get_states', '_get_statusBar', '_get_table', '_get_tableID', '_get_treeInterceptor', '_get_treeInterceptorClass', '_get_value', '_get_windowClassName', '_get_windowControlID', '_get_windowStyle', '_get_windowText', '_get_windowThreadID', '_isEqual', '_mouseEntered', '_processIDThreadID', '_propertyCache', '_set_treeInterceptor', '_speakObjectPropertiesCache', '_tableHeaderTextHelper', '_treeInterceptor', '_windowClassName', 'actionCount', 'activeChild', 'allowIAccessibleChildIDAndChildCountForPositionInfo', 'appModule', 'basicText', 'beTransparentToMouse', 'bindGesture', 'bindGestures', 'cachePropertiesByDefault', 'cellCoordsText', 'childCount', 'children', 'clearGestureBindings', 'columnCount', 'columnHeaderText', 'columnNumber', 'container', 'correctAPIForRelation', 'decodedAccDescription', 'defaultActionIndex', 'description', 'devInfo', 'displayText', 'doAction', 'embeddingTextInfo', 'event_IA2AttributeChange', 'event_alert', 'event_becomeNavigatorObject', 'event_caret', 'event_childID', 'event_descriptionChange', 'event_focusEntered', 'event_foreground', 'event_gainFocus', 'event_mouseMove', 'event_nameChange', 'event_objectID', 'event_selection', 'event_selectionAdd', 'event_selectionRemove', 'event_selectionWithIn', 'event_stateChange', 'event_typedCharacter', 'event_valueChange', 'event_windowHandle', 'findBestAPIClass', 'findOverlayClasses', 'firstChild', 'flatReviewPosition', 'flowsFrom', 'flowsTo', 'focusRedirect', 'getActionName', 'getChild', 'getPossibleAPIClasses', 'getScript', 'groupName', 'hasEncodedAccDescription', 'hasFocus', 'indexInParent', 'invalidateCache', 'invalidateCaches', 'isDuplicateIAccessibleEvent', 'isFocusable', 'isInForeground', 'isPointInObject', 'isPresentableFocusAncestor', 'isProtected', 'isWindowUnicode', 'keyboardShortcut', 'kwargsFromSuper', 'labeledBy', 'lastChild', 'location', 'locationText', 'makeTextInfo', 'name', 'next', 'normalizeWindowClassName', 'normalizedWindowClassNameCache', 'objectFromPoint', 'objectInForeground', 'objectWithFocus', 'parent', 'positionInfo', 'presType_content', 'presType_layout', 'presType_unavailable', 'presentationType', 'previous', 'processHandle', 'processID', 're_positionInfoEncodedAccDescription', 'recursiveDescendants', 'redraw', 'removeGestureBinding', 'reportFocus', 'role', 'rowCount', 'rowHeaderText', 'rowNumber', 'scrollIntoView', 'setFocus', 'shouldAllowIAccessibleFocusEvent', 'shouldCreateTreeInterceptor', 'simpleFirstChild', 'simpleLastChild', 'simpleNext', 'simpleParent', 'simplePrevious', 'sleepMode', 'states', 'statusBar', 'table', 'tableID', 'textRepresentationLineLength', 'treeInterceptor', 'treeInterceptorClass', 'value', 'windowClassName', 'windowControlID', 'windowHandle', 'windowStyle', 'windowText', 'windowThreadID']
(sorry, the lines are not properly wrapped, it is just for illustration)

NVDA (my screen reader) translates objects to some kind of base objects. Thus, a Java button will be the same as a WXWidgets button.
However, the control types can be rearranged anyway we like either by defining new classes or by modifying single properties from a class.

If a text is assigned to 'Description', a keybinding can be created and the text spoken.
It is clear that an additional Audacity module has to be created to make the additional features available.
For instance:

Code: Select all

# Audacity App Module for NVDA

import appModuleHandler
import api
import ui

class AppModule(appModuleHandler.AppModule):

	def script_announceWindowClassName(self, gesture):
		focusObj = api.getFocusQqqqqqqObject()
		name = focusObj.name
		windowClassName = focusObj.windowClassName
		ui.message("class for %s window: %s" % (name, windowClassName))

	def script_announceWindowControlID(self, gesture):
		focusObj = api.getFocusObject()
		name = focusObj.name
		windowControlID = focusObj.windowControlID
		ui.message("Control ID for %s window: %d" % (name, windowControlID))

	__gestures = {
		"kb:NVDA+leftArrow": "announceWindowClassName",
		"kb:NVDA+rightArrow": "announceWindowControlID",
	}
The currently shipped Audacity module is very simple: it just removes '&' in e.g. menus and buttons. There's a lot of space still available...

Re: Display label count

Posted: Tue Oct 28, 2014 10:28 pm
by Edgar
Robert J. H. wrote:Hi Edgar, thanks for taking the time.
That whooshing sound you just heard is the sound of your explanation going right over my head <grin>. Between the two of us I'm sure we can get this to work.

From what I can understand, the Track Info Panel looks (to the screen reader) like a window. That window has a bunch of "things" which can be accessed with various functions (e.g. _get_basictext). So, if we were to tell the screen reader:
Say focusObject._get_basictext
the user would hear whatever Audacity had put into the variable basictext. If that's accurate:
1) If basictext is already being used, or is inappropriate, are any of the other existing functions/variables better for this job?
2) Do you have any idea where, in the Audacity source code, these variables are filled?

Re: Display label count

Posted: Wed Oct 29, 2014 3:33 am
by Edgar
If we add this new function (Get Description) to TrackInfo.h at or near line number 100:

Code: Select all

class AUDACITY_DLL_API TrackInfo
{
public:
   TrackInfo(wxWindow * pParentIn);
   ~TrackInfo();

   int GetTrackInfoWidth() const;

   void UpdateSliderOffset(Track *t);
   
   wxAccStatus GetDescription(int WXUNUSED(childId), wxString * pDescription);//Add this
then in TrackInfo.cpp at the very bottom of the file (for simplicity):

Code: Select all

wxAccStatus GetDescription(int WXUNUSED(childId), wxString * pDescription) {
   wxString description (_("this is a test"));
   pDescription = &description;
         return wxACC_OK;
}
Will your screen reader say "this is a test" when you ask it to Get Description? GetDescription is a wxWidgets wxUSE_ACCESSIBILITY feature of wxAccessibleBase.

Re: Display label count

Posted: Wed Oct 29, 2014 9:50 am
by Robert J. H.
Edgar wrote:If we add this new function (Get Description) to TrackInfo.h at or near line number 100:

Code: Select all

class AUDACITY_DLL_API TrackInfo
{
public:
   TrackInfo(wxWindow * pParentIn);
   ~TrackInfo();

   int GetTrackInfoWidth() const;

   void UpdateSliderOffset(Track *t);
   
   wxAccStatus GetDescription(int WXUNUSED(childId), wxString * pDescription);//Add this
then in TrackInfo.cpp at the very bottom of the file (for simplicity):

Code: Select all

wxAccStatus GetDescription(int WXUNUSED(childId), wxString * pDescription) {
   wxString description (_("this is a test"));
   pDescription = &description;
         return wxACC_OK;
}
Will your screen reader say "this is a test" when you ask it to Get Description? GetDescription is a wxWidgets wxUSE_ACCESSIBILITY feature of wxAccessibleBase.
I have no TrackInfo.h/cpp in the source directory 'C:Audacity'.

Should those definitions go into TrackPanelAx.*?

Re: Display label count

Posted: Wed Oct 29, 2014 3:32 pm
by Edgar
Robert J. H. wrote: I have no TrackInfo.h/cpp in the source directory 'C:Audacity'.

Should those definitions go into TrackPanelAx.*?
My bad! TrackPanel.h/cpp.

In my defense, with the exception of a couple of very small classes whose definitions and declarations (headers and C++ files) are very short, almost every class (TrackPanel & TrackInfoPanel are both classes) has its own separate .h &.cpp files. At 796 lines Track Panel.h is very long for a header file, at 9599 lines TrackPanel.cpp is extremely long. I vote that they be split up into two separate sets of files.

Re: Display label count

Posted: Wed Oct 29, 2014 3:50 pm
by Robert J. H.
Edgar wrote:
Robert J. H. wrote: I have no TrackInfo.h/cpp in the source directory 'C:Audacity'.

Should those definitions go into TrackPanelAx.*?
My bad! TrackPanel.h/cpp.

In my defense, with the exception of a couple of very small classes whose definitions and declarations (headers and C++ files) are very short, almost every class (TrackPanel & TrackInfoPanel are both classes) has its own separate .h &.cpp files. At 796 lines Track Panel.h is very long for a header file, at 9599 lines TrackPanel.cpp is extremely long. I vote that they be split up into two separate sets of files.
The same with AudioIO, when I recall correctly.

Anyways, have you looked at TrackPanelAx?
There's already a getDescription definition in an If Clause (around line 233).

Code: Select all

// Returns the description for this object or a child.
wxAccStatus TrackPanelAx::GetDescription( int WXUNUSED(childId), wxString *description )
{
   description->Clear();

   return wxACC_OK;
}
Is that in any way helpful?

I'm going to try your code from above.

Re: Display label count

Posted: Wed Oct 29, 2014 4:12 pm
by Edgar
Robert J. H. wrote:
Edgar wrote:
Robert J. H. wrote: I have no TrackInfo.h/cpp in the source directory 'C:Audacity'.

Should those definitions go into TrackPanelAx.*?
My bad! TrackPanel.h/cpp.

In my defense, with the exception of a couple of very small classes whose definitions and declarations (headers and C++ files) are very short, almost every class (TrackPanel & TrackInfoPanel are both classes) has its own separate .h &.cpp files. At 796 lines Track Panel.h is very long for a header file, at 9599 lines TrackPanel.cpp is extremely long. I vote that they be split up into two separate sets of files.
The same with AudioIO, when I recall correctly.

Anyways, have you looked at TrackPanelAx?
There's already a getDescription definition in an If Clause (around line 233).

Code: Select all

// Returns the description for this object or a child.
wxAccStatus TrackPanelAx::GetDescription( int WXUNUSED(childId), wxString *description )
{
   description->Clear();

   return wxACC_OK;
}
Is that in any way helpful?

I'm going to try your code from above.

Code: Select all

class TrackPanelAx
brief Helper to TrackPanel to give accessibility.
Right concept. wrong class; again the split between TrackPanel & TrackInfo. My code might work as a test but for finished product we want a TrackInfoAx (which I would prefer to name TrackInfoAccessibility while renaming TrackPanelAx to TrackPanelAccessibility <grin>).
*edit 29 Oct 14 - class name spelling

Re: Display label count

Posted: Wed Oct 29, 2014 7:20 pm
by Edgar
If (as a test) the above did not work (and it probably did not)...I have made a first tab at TrackInfoAx but really have no understanding of how to test it with a screen reader. I just put the "this is a test" string into the built-in GetDescription.

patch attached (Warning - this patch is for testing only and may only compile/run In the wx3-Debug and the wx3-Release configurations. As mentioned in a –devel thread, MS VS 2013 is enforcing a lot of formatting changes which the Developers have not decided whether to accept and commit or figure out some way of bypassing; this makes this patch overly large and contain a lot of white space changes. I'm also having some problems getting some of the recent real-time effects code to compile in all four configurations.)

Re: Display label count

Posted: Wed Oct 29, 2014 9:10 pm
by Robert J. H.
Edgar wrote:If (as a test) the above did not work (and it probably did not)...I have made a first tab at TrackInfoAx but really have no understanding of how to test it with a screen reader. I just put the "this is a test" string into the built-in GetDescription.

patch attached (Warning - this patch is for testing only and may only compile/run In the wx3-Debug and the wx3-Release configurations. As mentioned in a –devel thread, MS VS 2013 is enforcing a lot of formatting changes which the Developers have not decided whether to accept and commit or figure out some way of bypassing; this makes this patch overly large and contain a lot of white space changes. I'm also having some problems getting some of the recent real-time effects code to compile in all four configurations.)
Admittedly, the above code (not the patch) does not work.
The description is still "None".

Have we already switched to WXW3.02?

I'm trying to build Rev13516, however, there are a zillion warnings (not related to WXWidgets though).

I somehow feel that the description should really defined in TrackPanelAx.
One simple solution to announcing a label track is to append 'Label Track' instead of 'Solo' and 'Mute' to 'Name' since those label tracks do not have this functionality. However, it has to be updated in the right place (i.e. focus change) and not when one presses solo on such a track...

The "GetDescription" method would be still helpful to display the Label counts.

Another strange thing is the property 'displayText'.
For tracks (children of 'Track Panel', interpreted as rows), it is empty (most of the time...), whereas it contains the rest of the text that is displayed in the track view (the 'table' or parent).
For instance: 'Audiotrack 44100Hz-1Mono-0.532 Bit Float(...)'.
In other words, the individual track properties are gathered on the table level (Track Panel) and not stored in a child's property--this audio (or Midi/Label) track information should actually also be in 'Description' imo.
What's more, the time intervals shouldn't be mixed in, of course.

By the way, NVDA is free and comes with the necessary tools to debug your patches.
If you want to try it, here are some basic commands:

- Insert or Caps lock serve as 'NVDA' key.
- NVDA+n opens the main menu.
- The speech can be turned off/silenced (Ctrl-NVDA+s, last entry)
- Instead, the speech viewer can be use (NVDA+n -->Tools-->Speech viewer)
- The Python console can be called directly (Ctrl-NVDA+z)
- The last object with focus gets automatically the name "focus" for the console.
- Thus, '>>> focus.description' should print the Unicode string for description.
- Console: F6 switches from interpreter to past output.
- Console: 'help(object) lists methods etc verbosely. dir(object) is also helpful.
- There's also the log viewer with extended information for the navigator object (i.e. the focus if not differently set with the NVDA+Numpad keys), to call with NVDA+F1.
- NVDA+1 toggles key description/help on and off.

However, I can of course perform the testing part, the latency will be terrible though.

(The post is only so long because I'm waiting for the built to finish :D )

Re: Display label count

Posted: Wed Oct 29, 2014 9:19 pm
by steve
Robert J. H. wrote:Have we already switched to WXW3.02?
No not yet. There has been some exploratory work, but there is currently a lot of other stuff going on, so Audacity is officially remaining with WxWidgets 2.8 for the next release.