Accessibility/SoftFocus: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
Line 57: Line 57:
     */  
     */  
   void setEnd(in long aEndOffset);
   void setEnd(in long aEndOffset);
 
   /*
   /*
     * Add an observer for pivot changes.
     * Add an observer for pivot changes.

Revision as of 04:03, 26 November 2011

Background

It is useful to have a focus-like state that is exclusive to accessibility and is independant of the DOM state. From the user's perspective this allows reviewing a document or web application without directly affecting its state, like moving the caret or cycling through focusable elements. This is useful in mobile, for example a user could navigate to a text entry without having it capture input. Only if the user chooses to enter text they would "activate" the text entry which would bring up an on screen keyboard, etc. This feature would also allow easier navigation of content.

Interfaces

nsIAccessibleVirtualPivot

interface nsIAccessiblePivot : nsISupports
{
  /*
   * The accessible the pivot is currently pointed at.
   */
  readonly attribute nsIAccessible accessible;

  /*
   * The document that owns this pivot.
   */
  readonly attribute nsIAccessibleDocument document;

  /*
   * The start offset in the accessible's text. Only supported when the accessible has
   * the nsIAccessibleText interface. If no explicit offset was set or if it is not
   * supported in the pivot's accessible this is -1.
   */
  readonly attribute long startOffset;

  /*
   * The end offset in the accessible's text. Only supported when the accessible has
   * the nsIAccessibleText interface. If no explicit offset was set or if it is not
   * supported in the pivot's accessible this is -1.
   */
  readonly attribute long endOffset;

  /*
   * Set the accessible this pivot should point to.
   *
   * @param aAccessible the new accessible to point to.
   * @throws NS_ERROR_INVALID_ARG when given accessible is not in the pivot's document.
   */ 
  void setAccessible(in nsIAccessible aAccessible);

  /*
   * Set the start offset in the pivot's accessible.
   *
   * @param aStartOffset the start offset to set.
   * @throws NS_ERROR_FAILURE when the pivot's accessible does not have the
   *   nsIAccessibleText inteface.
   */ 
  void setStart(in long aStartOffset);

  /*
   * Set the end offset in the pivot's accessible.
   *
   * @param aEndOffset the end offset to set.
   * @throws NS_ERROR_FAILURE when the pivot's accessible does not have the
   *   nsIAccessibleText inteface.
   */ 
  void setEnd(in long aEndOffset);

  /*
   * Add an observer for pivot changes.
   *
   * @param aObserver the observer object to be notified of pivot changes.
   */
  void addObserver(in nsIAccessibleVirtualPivotObserver aObserver);
}

nsIAccessibleVirtualPivotObserver

interface nsIAccessibleVirtualPivotObserver : nsISupports
{
  /**
   * Called when accessible of pivot changes.
   */
  void onAccessibleChanged(in nsIAccessible aOldAccessible, in nsIAccessible aNewAccessible);

  /**
   * Called when text offset changes.
   */
  void onTextOffsetChanged(in long aOldStart, in long aOldEnd,
                           in long aNewStart, in long aNewEnd);
}

nsIAccessibleDocument

interface nsIAccessibleDocument : nsISupports
{
  ...
  /**
   * The virtual cursor pivot for this document.
   */
  readonly attribute nsIAccessibleVirtualPivot virtualCursor;

  /**
   * Create a new pivot in this document.
   */
  nsIAccessibleVirtualPivot createVirtualPivot();
}

Events

A pivot change would fire an nsIAccessibleEvent event of type EVENT_VIRTUAL_PIVOT_CHANGED with the accessible attribute being the pivot's owner document. If the pivot is the document's virtual cursor an additional event of type EVENT_VIRTUAL_CURSOR_CHANGED is fired. Both event types support the following interface:

nsIAccessibleVirtualPivotChangedEvent

interface nsIAccessibleVirtualPivotChangedEvent : nsISupports
{
  /**
   * The pivot that changed.
   */
  readonly attribute nsIAccessibleVirtualPivot pivot;

  /**
   * The previous accessible the pivot pointed at or null.
   */
  readonly attribute nsIAccessible previousAccessible;

  /**
   * The previous start offset of the pivot or -1.
   */
  readonly attribute long previousStartOffset;

  /**
   * The previous end offset of the pivot or -1.
   */
  readonly attribute long previousEndOffset;
}

Example Usage

Setting Virtual Cursor

An input event handler that changes the virtual cursor.

function inputEventHandler(event) {
  ...
  treeWalker.currentNode = docAcc.virtualCursor.accessible;
  if (treeWalker.next())
    docAcc.virtualCursor.setAccessible(treeWalker.currentNode);
}

Presenting Virtual Cursor

An event listener that draws a ring for the virtual cursor. drawRect() is left to your imagination.

function handleEvent(aEvent) {
  if (aEvent.type != EVENT_VIRTUAL_CURSOR_CHANGED)
    return;

  let pivotEvent = aEvent.QueryInterface(nsIAccessibleVirtualPivotChangedEvent);

  showVirtualCursorRing(pivotEvent.accessible,
                        pivotEvent.startOffset,
                        pivotEvent.endOffset);
}

function showVirtualCursorRing (aAccessible, aStartOffset, aEndOffset) {
  let x = {};
  let y = {};
  let w = {};
  let h = {};

  if (aStartOffset >= 0 && aEndOffset >= 0) {
    try {
      let textAcc = aAccessible.QueryInterface(nsIAccessibleText);
      let start = {};
      let end = {};
      textAcc.getRangeExtents(aStartOffset, aEndOffset, x, y, w, h,
                              COORDTYPE_SCREEN_RELATIVE);
      drawRect(x.value, y.value, w.value, h.value);
      return;
    } catch (e) {
    }
  }

  aAccessible.getBounds(x, y, w, h);
  drawRect(x.value, y.value, w.value, h.value);
}