NVDAObject Class Map Ideas

Current Implementation

  • NVDAObjects are packaged in a hyerarchy which represents the API they support (e.g. MSAA NVDAObjects are in the IAccessible dir, Java Access Bridge objects are in the JAB dir).
  • When an IAccessible NVDAObject is instanciated, it is forced to a subclass of IAccessible, if a map exists in an IAccessible-specific class map, which maps from a windowClassName, accRole pare to an IAccessible NVDAObject subclass. This class map is stored in the same module the base IAccessible NVDAObject is.
  • No other API has a class map -- They usually only have one NVDAObject class which tries to handle all situations

The current problem

  • A user can not edit the IAccessible class map when running a compiled version of NVDA
  • The IAccessible class map can not handle whilecard or regexp matches (which may be needed for Delphy or .net window class names (which tend to be either dynamically generated, or have developer-specific strings appended/prepended to them).
  • There is no way to provide mappings for any other API (such as JAB or IAccessible2).
  • There is no way to provide appModule specific class mappings; appModules currently override class after the object is instanciated.

Proposed changes

Implement a file containing class mappings

A file should exist that is accessible to the user, that contains rules that tell NVDA what NVDAObject class to use, based on particular properties. These rules may look slightly like Linux UDev rules. The rules should allow to match in several different ways such as:

  • a==b (exact comparison)
  • a in b (for sets such as state flags)
  • simple match with whilecards
  • Regular expressions.

A mapping can be made up of multiple matches using multiple properties e.g. window::className=="Edit", IAccessible::accRole==ROLE_SYSTEM_DOCUMENT. Properties should contain namespaces some how to indicate clearly what API they are for. There also should be a property that always exists, that indicates the current API (such as IAccessible, JAB etc). It possibly might be good to indicate multiple current APIs (such as IAccessible and Window), though perhaps only one for now. Properties that APIs can provided obviously will be limited, for instance IAccessible probably wouldn't provide accname, accValue, accDescription etc as there could be a performance hit collecting these. Though, depending on caching, perhaps this may be possible in future. Finally, the end of the rule must point to a specific NVDAObject class (or possibly classes) that should be used to instanciate the object. If multiple classes are supported, then a new class should be dynamically generated based on the multiple classes given (example: IAccessible and RichEdit? Window). Perhaps at first though we only support one class for simplicity.

An NVDAObjecthandler module for generalizing NVDAObject class selection and instanciation

An NVDAObjecthandler module should be created that contains a few functions to standardize the way NVDAObjects are selected and instanciated. Perhaps something like selectClass(**properties) -- which would use the given properties to search the class map and or use hard-coded logic to choose an appropriate base API class, the function would return the class. And createNVDAObject(class,*args,**kwargs) -- which would actually instanciate the selected class, with the given arguments. Having these functions would not only allow the ease of searching the class map, but it would also allow hooking in to appModules etc before the class is instanciated, so that the appModule can have a say in what class should be used. Another idea may be to just merge selectClass and createNVDAObject in to a single createNVDAObject function, and then this means that any properties passed in to select, can then be cached on the object for later use (for example if accRole is used to select, then we shouldn't really have to call accRole again on the instanciated object for the role property).