[orca] Refactor speech generators to be table driven



commit 288641a4c30312f3979bc63e50deaffba004dcb9
Author: Willie Walker <william walker sun com>
Date:   Fri May 29 13:26:28 2009 -0400

    Refactor speech generators to be table driven
    
    First phase of working on bug #Bug 570658 â?? Refactor the speech
    and braille generators.  This phase touches the speech
    generators and makes things very much table driven (see the
    formatting.py modules).  Aside from touching many modules, the
    impact on the user should *hopefully* be unnoticeable.  That is,
    the new tables are set up to provide the same speech output we
    were getting before the refactor.  The next phases will be
    migrating where am I support to the speech generator and then
    working on braille.
---
 ChangeLog                                          |  173 ++
 po/POTFILES.in                                     |    4 +-
 src/orca/Makefile.am                               |    3 +-
 src/orca/bookmarks.py                              |    7 +-
 src/orca/default.py                                |  295 +---
 src/orca/formatting.py                             |  256 +++
 src/orca/liveregions.py                            |   10 +-
 src/orca/mouse_review.py                           |    5 +-
 src/orca/orca-setup.glade                          |    2 +-
 src/orca/script.py                                 |   10 +-
 src/orca/scripts/apps/Thunderbird/script.py        |    6 +-
 .../scripts/apps/Thunderbird/speech_generator.py   |   67 +-
 src/orca/scripts/apps/acroread.py                  |   12 +-
 src/orca/scripts/apps/evolution/Makefile.am        |    9 +-
 src/orca/scripts/apps/evolution/formatting.py      |   50 +
 src/orca/scripts/apps/evolution/script.py          |   38 +-
 .../scripts/apps/evolution/speech_generator.py     |   46 +-
 .../scripts/apps/gcalctool/speech_generator.py     |   14 +-
 src/orca/scripts/apps/gcalctool/where_am_i.py      |    2 +-
 src/orca/scripts/apps/gedit/script.py              |    7 +-
 src/orca/scripts/apps/gnome-system-monitor.py      |    2 +-
 src/orca/scripts/apps/gnome-terminal.py            |    4 +-
 .../apps/gnome-window-properties/Makefile.am       |    7 +-
 .../apps/gnome-window-properties/formatting.py     |   45 +
 .../scripts/apps/gnome-window-properties/script.py |   14 +-
 .../gnome-window-properties/speech_generator.py    |   59 -
 src/orca/scripts/apps/liferea.py                   |    4 +-
 src/orca/scripts/apps/pidgin/speech_generator.py   |  138 +-
 src/orca/scripts/apps/pidgin/where_am_i.py         |    8 +-
 src/orca/scripts/apps/planner/Makefile.am          |    8 +-
 src/orca/scripts/apps/planner/script.py            |    6 +-
 src/orca/scripts/apps/planner/speech_generator.py  |   75 +-
 src/orca/scripts/apps/rhythmbox/Makefile.am        |    1 +
 src/orca/scripts/apps/rhythmbox/formatting.py      |   52 +
 src/orca/scripts/apps/rhythmbox/script.py          |   10 +-
 .../scripts/apps/rhythmbox/speech_generator.py     |   69 +-
 src/orca/scripts/apps/soffice/Makefile.am          |    3 +-
 src/orca/scripts/apps/soffice/formatting.py        |   62 +
 src/orca/scripts/apps/soffice/script.py            |   31 +-
 src/orca/scripts/apps/soffice/speech_generator.py  |  574 +++----
 src/orca/scripts/apps/soffice/where_am_i.py        |   10 +-
 src/orca/scripts/apps/yelp.py                      |    3 +-
 src/orca/scripts/toolkits/Gecko/Makefile.am        |    3 +-
 src/orca/scripts/toolkits/Gecko/bookmarks.py       |    2 +-
 src/orca/scripts/toolkits/Gecko/formatting.py      |   84 +
 src/orca/scripts/toolkits/Gecko/script.py          |   42 +-
 .../scripts/toolkits/Gecko/speech_generator.py     |  876 +++-------
 src/orca/scripts/toolkits/Gecko/where_am_i.py      |   46 +-
 .../toolkits/J2SE-access-bridge/Makefile.am        |    3 +-
 .../toolkits/J2SE-access-bridge/__init__.py        |    2 +-
 .../toolkits/J2SE-access-bridge/formatting.py      |   51 +
 .../scripts/toolkits/J2SE-access-bridge/script.py  |   11 +-
 .../J2SE-access-bridge/speech_generator.py         |   51 +
 .../toolkits/J2SE-access-bridge/speechgenerator.py |  141 --
 src/orca/speech.py                                 |  122 +-
 src/orca/speech_generator.py                       | 1447 +++++++++++++++
 src/orca/speechgenerator.py                        | 1927 --------------------
 src/orca/structural_navigation.py                  |   24 +-
 src/orca/where_am_I.py                             |  126 +-
 test/harness/.gitignore                            |    5 +
 test/harness/runone.sh                             |    4 +-
 test/keystrokes/firefox/bug_511389.py              |    2 -
 test/keystrokes/firefox/bug_544771.py              |    3 -
 test/keystrokes/firefox/bug_552887a.py             |    2 +-
 test/keystrokes/firefox/bug_568631.py              |    7 +-
 test/keystrokes/firefox/codetalks_alert.py         |    1 -
 test/keystrokes/firefox/codetalks_button.py        |    9 +-
 test/keystrokes/firefox/codetalks_tree.py          |   19 +-
 test/keystrokes/firefox/codetalks_treegrid.py      |   25 +-
 test/keystrokes/firefox/dojo_button.py             |   74 +-
 test/keystrokes/firefox/dojo_checkbox.py           |    9 +-
 test/keystrokes/firefox/dojo_combo_box.py          |   22 +-
 test/keystrokes/firefox/dojo_dialog.py             |   12 +-
 test/keystrokes/firefox/dojo_panel_text.py         |    6 +-
 test/keystrokes/firefox/dojo_slider.py             |   10 +-
 test/keystrokes/firefox/dojo_spinner.py            |    8 +-
 test/keystrokes/firefox/dojo_tabcontainer.py       |   11 +-
 test/keystrokes/firefox/dojo_tree.py               |   31 +-
 test/keystrokes/firefox/find_wiki.py               |    5 +-
 test/keystrokes/firefox/flat_review_combo_box.py   |    7 +-
 test/keystrokes/firefox/html_role_combo_box.py     |   46 +-
 test/keystrokes/firefox/html_role_links.py         |   24 +-
 test/keystrokes/firefox/html_role_lists.py         |   12 +-
 .../firefox/html_struct_nav_blockquote.py          |   19 +-
 test/keystrokes/firefox/imagemap.py                |   36 -
 test/keystrokes/firefox/label_guess_bug_546815.py  |    3 +-
 .../firefox/label_guess_bugzilla_search.py         |   23 -
 .../keystrokes/firefox/line_nav_bugzilla_search.py |   12 +-
 test/keystrokes/firefox/line_nav_slash_test.py     |    3 +-
 test/keystrokes/firefox/line_nav_wiki.py           |    4 +-
 test/keystrokes/firefox/link_where_am_i.py         |   13 +-
 test/keystrokes/firefox/moz_checkbox.py            |   12 +-
 test/keystrokes/firefox/moz_menu.py                |   23 +-
 test/keystrokes/firefox/moz_progressbar.py         |    1 -
 test/keystrokes/firefox/moz_slider.py              |   11 +-
 test/keystrokes/firefox/moz_tabpanel.py            |   20 +-
 test/keystrokes/firefox/ms_tree_bug_570571.py      |   31 +-
 test/keystrokes/firefox/page_summary.py            |    7 +-
 test/keystrokes/firefox/sayAll_bugzilla_search.py  |    6 +-
 test/keystrokes/firefox/sayAll_role_combo_box.py   |    4 +-
 test/keystrokes/firefox/sayAll_wiki.py             |    4 +-
 test/keystrokes/firefox/tpg_aria_slider.py         |    8 -
 test/keystrokes/firefox/uiuc_alert.py              |    4 +-
 test/keystrokes/firefox/uiuc_button.py             |   10 +-
 test/keystrokes/firefox/uiuc_grid.py               |   15 +-
 test/keystrokes/firefox/uiuc_radiobutton.py        |   19 +-
 test/keystrokes/firefox/uiuc_slider.py             |    8 +-
 test/keystrokes/firefox/uiuc_tabpanel.py           |   12 +-
 test/keystrokes/firefox/uiuc_tree.py               |   41 +-
 test/keystrokes/firefox/xul_role_accel_label.py    |   11 +-
 test/keystrokes/firefox/xul_role_alert.py          |    3 -
 test/keystrokes/firefox/xul_role_check_box.py      |    9 +-
 .../keystrokes/firefox/xul_role_check_menu_item.py |   11 +-
 test/keystrokes/firefox/xul_role_combo_box.py      |   26 +-
 test/keystrokes/firefox/xul_role_entry.py          |    8 +-
 test/keystrokes/firefox/xul_role_list_item.py      |    6 +-
 test/keystrokes/firefox/xul_role_menu_bar.py       |   13 +-
 test/keystrokes/firefox/xul_role_page_tab.py       |   12 +-
 test/keystrokes/firefox/xul_role_push_button.py    |    5 +-
 test/keystrokes/firefox/xul_role_radio_button.py   |   16 +-
 .../keystrokes/firefox/xul_role_radio_menu_item.py |   21 +-
 test/keystrokes/firefox/xul_role_tree.py           |   44 +-
 test/keystrokes/firefox/xul_role_tree_table.py     |   17 +-
 .../firefox/xul_where_am_i_status_bar.py           |   12 +-
 test/keystrokes/firefox/yahoo_tab_view.py          |   14 +-
 test/keystrokes/gtk-demo/role_accel_label.py       |   13 +-
 test/keystrokes/gtk-demo/role_alert.py             |    2 -
 test/keystrokes/gtk-demo/role_check_box.py         |   14 +-
 test/keystrokes/gtk-demo/role_check_menu_item.py   |    9 +-
 test/keystrokes/gtk-demo/role_column_header.py     |   77 +-
 test/keystrokes/gtk-demo/role_combo_box.py         |   47 +-
 test/keystrokes/gtk-demo/role_combo_box2.py        |   15 +-
 test/keystrokes/gtk-demo/role_dialog.py            |    9 +-
 test/keystrokes/gtk-demo/role_icon.py              |   32 +-
 test/keystrokes/gtk-demo/role_label.py             |   25 +-
 test/keystrokes/gtk-demo/role_menu.py              |   32 +-
 test/keystrokes/gtk-demo/role_page_tab.py          |   17 +-
 test/keystrokes/gtk-demo/role_push_button.py       |   15 +-
 test/keystrokes/gtk-demo/role_radio_button.py      |   17 +-
 test/keystrokes/gtk-demo/role_radio_menu_item.py   |   18 +-
 test/keystrokes/gtk-demo/role_spin_button.py       |   25 +-
 test/keystrokes/gtk-demo/role_split_pane.py        |    5 +-
 test/keystrokes/gtk-demo/role_table.py             |   45 +-
 .../keystrokes/gtk-demo/role_tear_off_menu_item.py |    2 -
 test/keystrokes/gtk-demo/role_text_multiline.py    |   28 +-
 test/keystrokes/gtk-demo/role_toggle_button.py     |   13 +-
 test/keystrokes/gtk-demo/role_toolbar.py           |   19 +-
 test/keystrokes/gtk-demo/role_tree_table.py        |  124 +-
 test/keystrokes/oowriter/bug_350219.py             |    3 +-
 test/keystrokes/oowriter/bug_361747.py             |    9 +-
 test/keystrokes/oowriter/bug_364765.py             |    4 +-
 test/keystrokes/oowriter/bug_382408.py             |    2 +-
 test/keystrokes/oowriter/bug_384893.py             |    6 +-
 test/keystrokes/oowriter/bug_385828.py             |   11 +-
 test/keystrokes/oowriter/bug_413909.py             |    1 -
 test/keystrokes/oowriter/bug_435201.py             |    6 +-
 test/keystrokes/oowriter/bug_435226.py             |   21 +-
 test/keystrokes/oowriter/bug_450210.py             |    1 -
 test/keystrokes/oowriter/bug_469367.py             |    3 +-
 test/keystrokes/oowriter/table-sample.odt          |  Bin 9900 -> 9266 bytes
 160 files changed, 3615 insertions(+), 5145 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7d03d5d..7bcdb8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,176 @@
+2009-05-29  Willie Walker <william.walker> and
+	    Mesar Hameed <mesar hameed gmail com>
+
+        * po/POTFILES.in:
+          src/orca/Makefile.am:
+          src/orca/bookmarks.py:
+          src/orca/default.py:
+          src/orca/espeechfactory.py:
+          src/orca/formatting.py:
+          src/orca/liveregions.py:
+          src/orca/mouse_review.py:
+          src/orca/orca-setup.glade:
+          src/orca/script.py:
+          src/orca/scripts/apps/Thunderbird/script.py:
+          src/orca/scripts/apps/Thunderbird/speech_generator.py:
+          src/orca/scripts/apps/acroread.py:
+          src/orca/scripts/apps/evolution/Makefile.am:
+          src/orca/scripts/apps/evolution/formatting.py:
+          src/orca/scripts/apps/evolution/script.py:
+          src/orca/scripts/apps/evolution/speech_generator.py:
+          src/orca/scripts/apps/gcalctool/speech_generator.py:
+          src/orca/scripts/apps/gcalctool/where_am_i.py:
+          src/orca/scripts/apps/gedit/script.py:
+          src/orca/scripts/apps/gnome-system-monitor.py:
+          src/orca/scripts/apps/gnome-terminal.py:
+          src/orca/scripts/apps/gnome-window-properties/Makefile.am:
+          src/orca/scripts/apps/gnome-window-properties/formatting.py:
+          src/orca/scripts/apps/gnome-window-properties/script.py:
+          src/orca/scripts/apps/gnome-window-properties/speech_generator.py:
+          src/orca/scripts/apps/liferea.py:
+          src/orca/scripts/apps/pidgin/speech_generator.py:
+          src/orca/scripts/apps/pidgin/where_am_i.py:
+          src/orca/scripts/apps/planner/Makefile.am:
+          src/orca/scripts/apps/planner/script.py:
+          src/orca/scripts/apps/planner/speech_generator.py:
+          src/orca/scripts/apps/rhythmbox/Makefile.am:
+          src/orca/scripts/apps/rhythmbox/formatting.py:
+          src/orca/scripts/apps/rhythmbox/script.py:
+          src/orca/scripts/apps/rhythmbox/speech_generator.py:
+          src/orca/scripts/apps/soffice/Makefile.am:
+          src/orca/scripts/apps/soffice/formatting.py:
+          src/orca/scripts/apps/soffice/script.py:
+          src/orca/scripts/apps/soffice/speech_generator.py:
+          src/orca/scripts/apps/soffice/where_am_i.py:
+          src/orca/scripts/apps/yelp.py:
+          src/orca/scripts/toolkits/Gecko/Makefile.am:
+          src/orca/scripts/toolkits/Gecko/bookmarks.py:
+          src/orca/scripts/toolkits/Gecko/formatting.py:
+          src/orca/scripts/toolkits/Gecko/script.py:
+          src/orca/scripts/toolkits/Gecko/speech_generator.py:
+          src/orca/scripts/toolkits/Gecko/where_am_i.py:
+          src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am:
+          src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py:
+          src/orca/scripts/toolkits/J2SE-access-bridge/formatting.py:
+          src/orca/scripts/toolkits/J2SE-access-bridge/script.py:
+          src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py:
+          src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py:
+          src/orca/speech.py:
+          src/orca/speech_generator.py:
+          src/orca/speechgenerator.py:
+          src/orca/structural_navigation.py:
+          src/orca/where_am_I.py:
+          test/harness/.gitignore:
+          test/harness/runone.sh:
+          test/keystrokes/firefox/bug_511389.py:
+          test/keystrokes/firefox/bug_544771.py:
+          test/keystrokes/firefox/bug_552887a.py:
+          test/keystrokes/firefox/bug_568631.py:
+          test/keystrokes/firefox/codetalks_alert.py:
+          test/keystrokes/firefox/codetalks_button.py:
+          test/keystrokes/firefox/codetalks_tree.py:
+          test/keystrokes/firefox/codetalks_treegrid.py:
+          test/keystrokes/firefox/dojo_button.py:
+          test/keystrokes/firefox/dojo_checkbox.py:
+          test/keystrokes/firefox/dojo_combo_box.py:
+          test/keystrokes/firefox/dojo_dialog.py:
+          test/keystrokes/firefox/dojo_panel_text.py:
+          test/keystrokes/firefox/dojo_slider.py:
+          test/keystrokes/firefox/dojo_spinner.py:
+          test/keystrokes/firefox/dojo_tabcontainer.py:
+          test/keystrokes/firefox/dojo_tree.py:
+          test/keystrokes/firefox/find_wiki.py:
+          test/keystrokes/firefox/flat_review_combo_box.py:
+          test/keystrokes/firefox/html_role_combo_box.py:
+          test/keystrokes/firefox/html_role_links.py:
+          test/keystrokes/firefox/html_role_lists.py:
+          test/keystrokes/firefox/html_struct_nav_blockquote.py:
+          test/keystrokes/firefox/imagemap.py:
+          test/keystrokes/firefox/label_guess_bug_546815.py:
+          test/keystrokes/firefox/label_guess_bugzilla_search.py:
+          test/keystrokes/firefox/line_nav_bugzilla_search.py:
+          test/keystrokes/firefox/line_nav_slash_test.py:
+          test/keystrokes/firefox/line_nav_wiki.py:
+          test/keystrokes/firefox/link_where_am_i.py:
+          test/keystrokes/firefox/moz_checkbox.py:
+          test/keystrokes/firefox/moz_menu.py:
+          test/keystrokes/firefox/moz_progressbar.py:
+          test/keystrokes/firefox/moz_slider.py:
+          test/keystrokes/firefox/moz_tabpanel.py:
+          test/keystrokes/firefox/ms_tree_bug_570571.py:
+          test/keystrokes/firefox/page_summary.py:
+          test/keystrokes/firefox/sayAll_bugzilla_search.py:
+          test/keystrokes/firefox/sayAll_role_combo_box.py:
+          test/keystrokes/firefox/sayAll_wiki.py:
+          test/keystrokes/firefox/tpg_aria_slider.py:
+          test/keystrokes/firefox/uiuc_alert.py:
+          test/keystrokes/firefox/uiuc_button.py:
+          test/keystrokes/firefox/uiuc_grid.py:
+          test/keystrokes/firefox/uiuc_radiobutton.py:
+          test/keystrokes/firefox/uiuc_slider.py:
+          test/keystrokes/firefox/uiuc_tabpanel.py:
+          test/keystrokes/firefox/uiuc_tree.py:
+          test/keystrokes/firefox/xul_role_accel_label.py:
+          test/keystrokes/firefox/xul_role_alert.py:
+          test/keystrokes/firefox/xul_role_check_box.py:
+          test/keystrokes/firefox/xul_role_check_menu_item.py:
+          test/keystrokes/firefox/xul_role_combo_box.py:
+          test/keystrokes/firefox/xul_role_entry.py:
+          test/keystrokes/firefox/xul_role_list_item.py:
+          test/keystrokes/firefox/xul_role_menu_bar.py:
+          test/keystrokes/firefox/xul_role_page_tab.py:
+          test/keystrokes/firefox/xul_role_push_button.py:
+          test/keystrokes/firefox/xul_role_radio_button.py:
+          test/keystrokes/firefox/xul_role_radio_menu_item.py:
+          test/keystrokes/firefox/xul_role_tree.py:
+          test/keystrokes/firefox/xul_role_tree_table.py:
+          test/keystrokes/firefox/xul_where_am_i_status_bar.py:
+          test/keystrokes/firefox/yahoo_tab_view.py:
+          test/keystrokes/gtk-demo/role_accel_label.py:
+          test/keystrokes/gtk-demo/role_alert.py:
+          test/keystrokes/gtk-demo/role_check_box.py:
+          test/keystrokes/gtk-demo/role_check_menu_item.py:
+          test/keystrokes/gtk-demo/role_column_header.py:
+          test/keystrokes/gtk-demo/role_combo_box.py:
+          test/keystrokes/gtk-demo/role_combo_box2.py:
+          test/keystrokes/gtk-demo/role_dialog.py:
+          test/keystrokes/gtk-demo/role_icon.py:
+          test/keystrokes/gtk-demo/role_label.py:
+          test/keystrokes/gtk-demo/role_menu.py:
+          test/keystrokes/gtk-demo/role_page_tab.py:
+          test/keystrokes/gtk-demo/role_push_button.py:
+          test/keystrokes/gtk-demo/role_radio_button.py:
+          test/keystrokes/gtk-demo/role_radio_menu_item.py:
+          test/keystrokes/gtk-demo/role_spin_button.py:
+          test/keystrokes/gtk-demo/role_split_pane.py:
+          test/keystrokes/gtk-demo/role_table.py:
+          test/keystrokes/gtk-demo/role_tear_off_menu_item.py:
+          test/keystrokes/gtk-demo/role_text_multiline.py:
+          test/keystrokes/gtk-demo/role_toggle_button.py:
+          test/keystrokes/gtk-demo/role_toolbar.py:
+          test/keystrokes/gtk-demo/role_tree_table.py:
+          test/keystrokes/oowriter/bug_350219.py:
+          test/keystrokes/oowriter/bug_361747.py:
+          test/keystrokes/oowriter/bug_364765.py:
+          test/keystrokes/oowriter/bug_382408.py:
+          test/keystrokes/oowriter/bug_384893.py:
+          test/keystrokes/oowriter/bug_385828.py:
+          test/keystrokes/oowriter/bug_413909.py:
+          test/keystrokes/oowriter/bug_435201.py:
+          test/keystrokes/oowriter/bug_435226.py:
+          test/keystrokes/oowriter/bug_450210.py:
+          test/keystrokes/oowriter/bug_469367.py:
+          test/keystrokes/oowriter/table-sample.odt:	
+	  First phase of working on bug #Bug 570658 â?? Refactor the speech
+	  and braille generators.  This phase touches the speech
+	  generators and makes things very much table driven (see the
+	  formatting.py modules).  Aside from touching many modules, the
+	  impact on the user should *hopefully* be unnoticeable.  That is,
+	  the new tables are set up to provide the same speech output we
+	  were getting before the refactor.  The next phases will be
+	  migrating where am I support to the speech generator and then
+	  working on braille.
+	
 2009-05-26  Joanmarie Diggs <joanmarie diggs gmail com>
 
         * src/orca/scripts/apps/ekiga.py:
diff --git a/po/POTFILES.in b/po/POTFILES.in
index cb2c1f1..8bc5e52 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -64,10 +64,10 @@ src/orca/scripts/toolkits/Gecko/speech_generator.py
 src/orca/scripts/toolkits/Gecko/structural_navigation.py
 src/orca/scripts/toolkits/Gecko/where_am_i.py
 src/orca/scripts/toolkits/J2SE-access-bridge/braillegenerator.py
-src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
+src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
 src/orca/settings.py
 src/orca/speechdispatcherfactory.py
-src/orca/speechgenerator.py
+src/orca/speech_generator.py
 src/orca/speechserver.py
 src/orca/speech.py
 src/orca/structural_navigation.py
diff --git a/src/orca/Makefile.am b/src/orca/Makefile.am
index 21ccabc..ef2a770 100644
--- a/src/orca/Makefile.am
+++ b/src/orca/Makefile.am
@@ -25,6 +25,7 @@ orca_python_PYTHON = \
 	find.py \
 	flat_review.py \
 	focus_tracking_presenter.py \
+	formatting.py \
 	gnomespeechfactory.py \
 	httpserver.py \
 	input_event.py \
@@ -55,7 +56,7 @@ orca_python_PYTHON = \
 	settings.py \
 	speech.py \
 	speechdispatcherfactory.py \
-	speechgenerator.py \
+	speech_generator.py \
 	speechserver.py \
 	structural_navigation.py \
 	text_attribute_names.py \
diff --git a/src/orca/bookmarks.py b/src/orca/bookmarks.py
index 3a95d66..7a86bec 100644
--- a/src/orca/bookmarks.py
+++ b/src/orca/bookmarks.py
@@ -77,9 +77,10 @@ class Bookmarks:
         # those spots.  These spots are known as 'bookmarks'. 
         #
         utterances = [_('bookmark entered')]
-        utterances.extend(self._script.speechGenerator.getSpeech( \
-                          context.getCurrentAccessible(), False))
-        speech.speakUtterances(utterances)
+        utterances.extend(
+            self._script.speechGenerator.getSpeech(
+                context.getCurrentAccessible()))
+        speech.speak(utterances)
 
     def bookmarkCurrentWhereAmI(self, inputEvent):
         """ Report "Where am I" information for this bookmark relative to the 
diff --git a/src/orca/default.py b/src/orca/default.py
index a18a6e6..69002e4 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -2048,17 +2048,17 @@ class Script(script.Script):
                 if not moved:
                     break
 
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
         elif self.isTextArea(orca_state.locusOfFocus):
             try:
                 orca_state.locusOfFocus.queryText()
             except NotImplementedError:
                 utterances = self.speechGenerator.getSpeech(
-                             orca_state.locusOfFocus, False)
+                    orca_state.locusOfFocus)
                 utterances.extend(self.tutorialGenerator.getTutorial(
                            orca_state.locusOfFocus, False))
-                speech.speakUtterances(utterances)
+                speech.speak(utterances)
             except AttributeError:
                 pass
             else:
@@ -2261,34 +2261,34 @@ class Script(script.Script):
         """Speaks the sentence prior to the caret, as long as there is
         a sentence prior to the caret and there is no intervening sentence
         delimiter between the caret and the end of the sentence.
- 
+
         The entry condition for this method is that the character
         prior to the current caret position is a sentence delimiter,
         and it's what caused this method to be called in the first
         place.
- 
+
         Arguments:
         - obj: an Accessible object that implements the AccessibleText
         interface.
         """
- 
+
         try:
             text = obj.queryText()
         except NotImplementedError:
             return
- 
+
         offset = text.caretOffset - 1
         previousOffset = text.caretOffset - 2
         if (offset < 0 or previousOffset < 0):
             return
- 
+
         [currentChar, startOffset, endOffset] = \
             text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
         [previousChar, startOffset, endOffset] = \
             text.getTextAtOffset(previousOffset, pyatspi.TEXT_BOUNDARY_CHAR)
         if not self.isSentenceDelimiter(currentChar, previousChar):
             return
- 
+
         # OK - we seem to be cool so far.  So...starting with what
         # should be the last character in the sentence (caretOffset - 2),
         # work our way to the beginning of the sentence, stopping when
@@ -2296,7 +2296,7 @@ class Script(script.Script):
         #
         sentenceEndOffset = text.caretOffset - 2
         sentenceStartOffset = sentenceEndOffset
- 
+
         while sentenceStartOffset >= 0:
             [currentChar, startOffset, endOffset] = \
                 text.getTextAtOffset(sentenceStartOffset,
@@ -2308,7 +2308,7 @@ class Script(script.Script):
                 break
             else:
                 sentenceStartOffset -= 1
- 
+
         # If we came across a sentence delimiter before hitting any
         # text, we really don't have a previous sentence.
         #
@@ -2323,17 +2323,17 @@ class Script(script.Script):
         else:
             sentence = self.getText(obj, sentenceStartOffset + 1,
                                          sentenceEndOffset + 1)
- 
+
         if self.getLinkIndex(obj, sentenceStartOffset + 1) >= 0:
             voice = self.voices[settings.HYPERLINK_VOICE]
         elif sentence.isupper():
             voice = self.voices[settings.UPPERCASE_VOICE]
         else:
             voice = self.voices[settings.DEFAULT_VOICE]
- 
+
         sentence = self.adjustForRepeats(sentence)
         speech.speak(sentence, voice)
- 
+
     def echoPreviousWord(self, obj, offset=None):
         """Speaks the word prior to the caret, as long as there is
         a word prior to the caret and there is no intervening word
@@ -2710,7 +2710,7 @@ class Script(script.Script):
                         percentage = _("%d percent.") % percentValue + " "
 
                         utterances.append(percentage)
-                        speech.speakUtterances(utterances)
+                        speech.speak(utterances)
 
                         self.lastProgressBarTime[obj] = currentTime
                         self.lastProgressBarValue[obj] = percentValue
@@ -2776,6 +2776,7 @@ class Script(script.Script):
         # Clear the point of reference.
         # If the point of reference is a cell, we want to keep the
         # table-related points of reference.
+        #
         if oldParent is not None and oldParent == newParent and \
               newParent.getRole() in [pyatspi.ROLE_TABLE,
                                       pyatspi.ROLE_TREE_TABLE]:
@@ -2788,154 +2789,14 @@ class Script(script.Script):
         if newLocusOfFocus:
             self.updateBraille(newLocusOfFocus)
 
-            utterances = []
-
-            # Now figure out how of the container context changed and
-            # speech just what is different.
-            #
-            commonAncestor = self.findCommonAncestor(oldLocusOfFocus,
-                                                     newLocusOfFocus)
-            if commonAncestor:
-                context = self.speechGenerator.getSpeechContext( \
-                                           newLocusOfFocus, commonAncestor)
-                utterances.append(" ".join(context))
-
-            # Now, we'll treat table row and column headers as context
-            # as well.  This requires special handling because we're
-            # making headers seem hierarchical in the context, but they
-            # are not hierarchical in the containment hierarchicy.
-            # We also only want to speak the one that changed.  If both
-            # changed, first speak the row header, then the column header.
-            #
-            # We also keep track of tree level depth and only announce
-            # that if it changes.
-            #
-            # Note that Java Swing allows things like ROLE_LABEL objects
-            # in trees and tables, so we'll check the parent's role to 
-            # see if it is a table.
-            #
-            oldNodeLevel = -1
-            newNodeLevel = -1
-            if (newLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL) \
-               or (newParent.getRole() == pyatspi.ROLE_TABLE):
-                try:
-                    table = oldParent.queryTable()
-                except:
-                    table = None
-                if table and \
-                      ((oldLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL) \
-                       or (oldParent.getRole() == pyatspi.ROLE_TABLE)):
-                    index = self.getCellIndex(oldLocusOfFocus)
-                    oldRow = table.getRowAtIndex(index)
-                    oldCol = table.getColumnAtIndex(index)
-                else:
-                    oldRow = -1
-                    oldCol = -1
-
-                try:
-                    table = newParent.queryTable()
-                except:
-                    pass
-                else:
-                    index = self.getCellIndex(newLocusOfFocus)
-                    newRow = table.getRowAtIndex(index)
-                    newCol = table.getColumnAtIndex(index)
-
-                    if (newRow >= 0) \
-                       and ((newRow != oldRow) or (oldParent != newParent)):
-                        # Get the header information.  In Java Swing, the
-                        # information is not exposed via the description
-                        # but is instead a header object, so we fall back
-                        # to that if it exists.
-                        #
-                        # [[[TODO: WDW - the more correct thing to do, I 
-                        # think, is to look at the row header object.
-                        # We've been looking at the description for so 
-                        # long, though, that we'll give the description 
-                        # preference for now.]]]
-                        #
-                        desc = table.getRowDescription(newRow)
-                        if not desc:
-                            header = table.getRowHeader(newRow)
-                            if header:
-                                desc = self.getDisplayedText(header)
-                        if desc and len(desc):
-                            text = desc
-                            if settings.speechVerbosityLevel \
-                                   == settings.VERBOSITY_LEVEL_VERBOSE:
-                                text += " " \
-                                        + rolenames.rolenames[\
-                                        pyatspi.ROLE_ROW_HEADER].speech
-                            utterances.append(text)
-                    if (newCol >= 0) \
-                       and ((newCol != oldCol) or (oldParent != newParent)):
-                        # Don't speak Thunderbird column headers, since
-                        # it's not possible to navigate across a row.
-                        topName = self.getTopLevelName(newLocusOfFocus)
-                        if not topName.endswith(" - Thunderbird"):
-                            # Get the header information.  In Java Swing, the
-                            # information is not exposed via the description
-                            # but is instead a header object, so we fall back
-                            # to that if it exists.
-                            #
-                            # [[[TODO: WDW - the more correct thing to do, I 
-                            # think, is to look at the row header object.
-                            # We've been looking at the description for so 
-                            # long, though, that we'll give the description 
-                            # preference for now.]]]
-                            #
-                            desc = table.getColumnDescription(newCol)
-                            if not desc:
-                                header = table.getColumnHeader(newCol)
-                                if header:
-                                    desc = self.getDisplayedText(header)
-                            cellText = self.getDisplayedText(newLocusOfFocus)
-                            if desc and len(desc) and cellText != desc:
-                                text = desc
-                                if settings.speechVerbosityLevel \
-                                       == settings.VERBOSITY_LEVEL_VERBOSE:
-                                    text += " " \
-                                            + rolenames.rolenames[\
-                                            pyatspi.ROLE_COLUMN_HEADER].speech
-                                utterances.append(text)
-
-            oldNodeLevel = self.getNodeLevel(oldLocusOfFocus)
-            newNodeLevel = self.getNodeLevel(newLocusOfFocus)
-
-            # We'll also treat radio button groups as though they are
-            # in a context, with the label for the group being the
-            # name of the context.
-            #
-            if newLocusOfFocus \
-               and newLocusOfFocus.getRole() == pyatspi.ROLE_RADIO_BUTTON:
-                radioGroupLabel = None
-                inSameGroup = False
-                relations = newLocusOfFocus.getRelationSet()
-                for relation in relations:
-                    if (not radioGroupLabel) \
-                        and (relation.getRelationType() \
-                             == pyatspi.RELATION_LABELLED_BY):
-                        radioGroupLabel = relation.getTarget(0)
-                    if (not inSameGroup) \
-                        and (relation.getRelationType() \
-                             == pyatspi.RELATION_MEMBER_OF):
-                        for i in range(0, relation.getNTargets()):
-                            target = relation.getTarget(i)
-                            if target == oldLocusOfFocus:
-                                inSameGroup = True
-                                break
-
-                # We'll only announce the radio button group when we
-                # switch groups.
-                #
-                if (not inSameGroup) and radioGroupLabel:
-                    utterances.append(self.getDisplayedText(radioGroupLabel))
-
             # Check to see if we are in the Pronunciation Dictionary in the
             # Orca Preferences dialog. If so, then we do not want to use the
             # pronunciation dictionary to replace the actual words in the
             # first column of this table.
             #
+            # [[[TODO: WDW - this should be pushed into an
+            # adjustForPronunciation method in a script for orca.]]]
+            #
             rolesList = [pyatspi.ROLE_TABLE_CELL, \
                          pyatspi.ROLE_TABLE, \
                          pyatspi.ROLE_SCROLL_PANE, \
@@ -2947,59 +2808,6 @@ class Script(script.Script):
             else:
                 orca_state.usePronunciationDictionary = True
 
-            # Get the text for the object itself.
-            #
-            utterances.extend(
-                self.speechGenerator.getSpeech(newLocusOfFocus, False))
-            utterances.extend(
-                self.tutorialGenerator.getTutorial(newLocusOfFocus, False))
-            # Now speak the new tree node level if it has changed.
-            #
-            if (oldNodeLevel != newNodeLevel) \
-               and (newNodeLevel >= 0):
-                # Translators: this represents the depth of a node in a tree
-                # view (i.e., how many ancestors a node has).
-                #
-                utterances.append(_("tree level %d") % (newNodeLevel + 1))
-
-            # If this is an icon within an layered pane or a table cell
-            # within a table or a tree table and the item is focused but not
-            # selected, let the user know. See bug #486908 for more details.
-            #
-            checkIfSelected = False
-            objRole, parentRole, state = None, None, None
-            if newLocusOfFocus:
-                objRole = newLocusOfFocus.getRole()
-                state = newLocusOfFocus.getState()
-                if newLocusOfFocus.parent:
-                    parentRole = newLocusOfFocus.parent.getRole()
-
-            if objRole == pyatspi.ROLE_TABLE_CELL and \
-               (parentRole == pyatspi.ROLE_TREE_TABLE or \
-                parentRole == pyatspi.ROLE_TABLE):
-                checkIfSelected = True
-
-            # If we met the last set of conditions, but we got here by
-            # moving left or right on the same row, then don't announce the
-            # selection state to the user. See bug #523235 for more details.
-            #
-            if checkIfSelected == True and \
-               (orca_state.lastNonModifierKeyEvent and \
-               (orca_state.lastNonModifierKeyEvent.event_string == "Left" or \
-               orca_state.lastNonModifierKeyEvent.event_string == "Right")):
-                checkIfSelected = False
-
-            if objRole == pyatspi.ROLE_ICON and \
-                parentRole == pyatspi.ROLE_LAYERED_PANE:
-                checkIfSelected = True
-
-            if checkIfSelected and state \
-               and not state.contains(pyatspi.STATE_SELECTED):
-                # Translators: this is in reference to a table cell being
-                # selected or not.
-                #
-                utterances.append(C_("tablecell", " not selected"))
-
             # We might be automatically speaking the unbound labels
             # in a dialog box as the result of the dialog box suddenly
             # appearing.  If so, don't interrupt this because of a
@@ -3010,18 +2818,23 @@ class Script(script.Script):
                 and self.windowActivateTime \
                 and ((time.time() - self.windowActivateTime) < 1.0)
 
-            if objRole == pyatspi.ROLE_LINK:
+            # [[[TODO: WDW - this should move to the generator.]]]
+            #
+            if newLocusOfFocus.getRole() == pyatspi.ROLE_LINK:
                 voice = self.voices[settings.HYPERLINK_VOICE]
             else:
                 voice = self.voices[settings.DEFAULT_VOICE]
 
-            speech.speakUtterances(utterances, voice, not shouldNotInterrupt)
+            utterances = self.speechGenerator.getSpeech(
+                newLocusOfFocus,
+                priorObj=oldLocusOfFocus)
+            speech.speak(utterances, voice, not shouldNotInterrupt)
 
             # If this is a table cell, save the current row and column
             # information in the table cell's table, so that we can use
             # it the next time.
             #
-            if objRole == pyatspi.ROLE_TABLE_CELL:
+            if newLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL:
                 try:
                     table = newParent.queryTable()
                 except:
@@ -3107,7 +2920,7 @@ class Script(script.Script):
                 for label in labels:
                     utterances.append(label.name)
 
-                speech.speakUtterances(utterances)
+                speech.speak(utterances)
 
                 return
 
@@ -3121,10 +2934,11 @@ class Script(script.Script):
                 target = relation.getTarget(0)
                 if target == orca_state.locusOfFocus:
                     self.updateBraille(target)
-                    utterances = self.speechGenerator.getSpeech(target, True)
+                    utterances = self.speechGenerator.getSpeech(
+                        target, already_focused=True)
                     utterances.extend(self.tutorialGenerator.getTutorial(
                                target, True))
-                    speech.speakUtterances(utterances)
+                    speech.speak(utterances)
                     return
 
         # If this object is a label, and if it has a LABEL_FOR relation
@@ -3140,10 +2954,10 @@ class Script(script.Script):
                     if target == orca_state.locusOfFocus:
                         self.updateBraille(target)
                         utterances = self.speechGenerator.getSpeech(
-                                     target, True)
+                            target, already_focused=True)
                         utterances.extend(self.tutorialGenerator.getTutorial(
                                           target, True))
-                        speech.speakUtterances(utterances)
+                        speech.speak(utterances)
                         return
 
         if not self.isSameObject(obj, orca_state.locusOfFocus):
@@ -3174,9 +2988,9 @@ class Script(script.Script):
 
         mag.magnifyAccessible(event, obj)
         self.updateBraille(obj)
-        utterances = self.speechGenerator.getSpeech(obj, True)
+        utterances = self.speechGenerator.getSpeech(obj, already_focused=True)
         utterances.extend(self.tutorialGenerator.getTutorial(obj, True))
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def updateBraille(self, obj, extraRegion=None):
         """Updates the braille display to show the give object.
@@ -3323,7 +3137,7 @@ class Script(script.Script):
 
     def _speakContiguousSelection(self, obj, relationship):
         """Check if the contiguous object has a selection. If it does, then
-        speak it. If the user pressed Shift-Down, then look for an object 
+        speak it. If the user pressed Shift-Down, then look for an object
         with a RELATION_FLOWS_FROM relationship. If they pressed Shift-Up,
         then look for a RELATION_FLOWS_TO relationship.
 
@@ -3359,7 +3173,7 @@ class Script(script.Script):
 
                 # When selecting down across paragraph boundaries, what
                 # we've (un)selected on (what is now) the previous line
-                # is from wherever the cursor used to be to the end of 
+                # is from wherever the cursor used to be to the end of
                 # the line.
                 #
                 if relationship == pyatspi.RELATION_FLOWS_FROM:
@@ -3396,7 +3210,7 @@ class Script(script.Script):
         return selSpoken
 
     def _presentTextAtNewCaretPosition(self, event, otherObj=None):
-        """Updates braille, magnification, and outputs speech for the 
+        """Updates braille, magnification, and outputs speech for the
         event.source or the otherObj."""
 
         obj = otherObj or event.source
@@ -3458,7 +3272,7 @@ class Script(script.Script):
                     # Shift+Up, what we've selected in this object starts
                     # with the current offset and goes to the end of the
                     # paragraph.
-                    # 
+                    #
                     if not self.isSameObject(lastPos[0], obj):
                         [startOffset, endOffset] = \
                             text.caretOffset, text.characterCount
@@ -3762,10 +3576,10 @@ class Script(script.Script):
         except NotImplementedError:
             return
 
-        # Pylint is confused and flags this and similar lines, with the 
+        # Pylint is confused and flags this and similar lines, with the
         # following error:
         #
-        # E1103:3673:Script.onTextInserted: Instance of 'str' has no 
+        # E1103:3673:Script.onTextInserted: Instance of 'str' has no
         #'caretOffset' member (but some types could not be inferred)
         #
         # But it does, so we'll just tell pylint that we know what we
@@ -3948,12 +3762,11 @@ class Script(script.Script):
                     and (orca_state.lastNonModifierKeyEvent.event_string \
                                                                   == "F1"):
                     self.updateBraille(orca_state.locusOfFocus)
-                    utterances = self.speechGenerator.getSpeech(\
-                        orca_state.locusOfFocus,
-                        False)
+                    utterances = self.speechGenerator.getSpeech(
+                        orca_state.locusOfFocus)
                     utterances.extend(self.tutorialGenerator.getTutorial(
                                       orca_state.locusOfFocus, False))
-                    speech.speakUtterances(utterances)
+                    speech.speak(utterances)
             return
 
         if event.source.getRole() in state_change_notifiers:
@@ -4089,7 +3902,7 @@ class Script(script.Script):
 
             # If there's a completely blank line in between our previous
             # and current locations, where we came from will lack any
-            # offically-selectable characters. As a result, we won't 
+            # offically-selectable characters. As a result, we won't
             # indicate when a blank line has been selected. Under these
             # conditions, we'll try to backtrack further.
             #
@@ -4109,8 +3922,8 @@ class Script(script.Script):
                     else:
                         break
 
-        self.speakTextSelectionState(obj, startOffset, endOffset)    
-            
+        self.speakTextSelectionState(obj, startOffset, endOffset)
+
     def onSelectionChanged(self, event):
         """Called when an object's selection changes.
 
@@ -4278,7 +4091,7 @@ class Script(script.Script):
                     # a document, Orca lets them know this.
                     #
                     utterances.append(C_("text", "selected"))
-                    speech.speakUtterances(utterances)
+                    speech.speak(utterances)
                 self.updateBraille(orca_state.locusOfFocus)
 
     def noOp(self, event):
@@ -4682,7 +4495,7 @@ class Script(script.Script):
             table = parent.queryTable()
         except NotImplementedError:
             table = None
-            
+
         if table:
             for i in range(0, table.nColumns):
                 header = table.getColumnHeader(i)
@@ -5284,10 +5097,10 @@ class Script(script.Script):
         #
         if not isinstance(inputEvent, input_event.BrailleEvent):
             utterances = self.speechGenerator.getSpeech(
-                    context.getCurrentAccessible(), False)
+                    context.getCurrentAccessible())
             utterances.extend(self.tutorialGenerator.getTutorial(
                     context.getCurrentAccessible(), False))
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
         return True
 
     def reviewPreviousItem(self, inputEvent):
@@ -6105,7 +5918,7 @@ class Script(script.Script):
         Returns a string representing the value.
         """
 
-        # Use ARIA "valuetext" attribute if present.  See 
+        # Use ARIA "valuetext" attribute if present.  See
         # http://bugzilla.gnome.org/show_bug.cgi?id=552965
         #
         attributes = obj.getAttributes()
@@ -6648,8 +6461,8 @@ class Script(script.Script):
 
     def isSentenceDelimiter(self, currentChar, previousChar):
         """Returns True if we are positioned at the end of a sentence.
-        This is determined by checking if the current character is a 
-        white space character and the previous character is one of the 
+        This is determined by checking if the current character is a
+        white space character and the previous character is one of the
         normal end-of-sentence punctuation characters.
 
         Arguments:
diff --git a/src/orca/espeechfactory.py b/src/orca/espeechfactory.py
old mode 100755
new mode 100644
diff --git a/src/orca/formatting.py b/src/orca/formatting.py
new file mode 100644
index 0000000..59f6318
--- /dev/null
+++ b/src/orca/formatting.py
@@ -0,0 +1,256 @@
+# Orca
+#
+# Copyright 2004-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Manages the formatting settings for Orca."""
+
+__id__        = "$Id:$"
+__version__   = "$Revision:$"
+__date__      = "$Date:$"
+__copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import copy
+
+import pyatspi
+
+# pylint: disable-msg=C0301
+
+formatting = {
+    'speech': {
+        'prefix': {
+            'focused': '[]',
+            'unfocused': 'newAncestors + newRowHeader + newColumnHeader + newRadioButtonGroup'
+            },
+        'suffix': {
+            'focused': '[]',
+            'unfocused': 'newNodeLevel + unselectedCell + tutorial'
+            },
+        'default': {
+            'focused': '[]',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+            },
+        pyatspi.ROLE_ALERT: {
+            'unfocused': 'labelAndName + unrelatedLabels'
+            },
+        pyatspi.ROLE_ANIMATION: {
+            'unfocused': 'labelAndName'
+            },
+        pyatspi.ROLE_CHECK_BOX: {
+            'focused': 'checkedState',
+            'unfocused': 'labelAndName + roleName + checkedState + required + availability'
+            },
+        pyatspi.ROLE_CHECK_MENU_ITEM: {
+            'focused': 'checkedState',
+            'unfocused': 'labelAndName + roleName + checkedState + required + availability + accelerator'
+            },
+        pyatspi.ROLE_COMBO_BOX: {
+            'focused': 'name',
+            },
+        pyatspi.ROLE_DIALOG: {
+            'unfocused': 'labelAndName + unrelatedLabels'
+            },
+        pyatspi.ROLE_ENTRY: {
+            'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+            'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+            },
+        pyatspi.ROLE_FRAME: {
+            'focused': '[]',
+            'unfocused': 'labelAndName + allTextSelection + roleName + unfocusedDialogCount + availability'
+            },
+        pyatspi.ROLE_ICON: {
+            'focused': 'labelAndName + imageDescription + roleName',
+            'unfocused': 'labelAndName + imageDescription + roleName'
+            },
+        pyatspi.ROLE_LAYERED_PANE: {
+            'focused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noShowingChildren'
+            },
+        pyatspi.ROLE_LIST_ITEM: {
+            'focused': 'expandableState + availability',
+            'unfocused': 'labelAndName + allTextSelection + expandableState + availability'
+            },
+        pyatspi.ROLE_MENU: {
+            'focused': '[]',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+            },
+        pyatspi.ROLE_MENU_ITEM: {
+            'focused': '[]',
+            'unfocused': 'labelAndName + menuItemCheckedState + availability + accelerator'
+            },
+        pyatspi.ROLE_PASSWORD_TEXT: {
+            'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+            'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+            },
+        pyatspi.ROLE_PROGRESS_BAR: {
+            'focused': 'percentage',
+            'unfocused': 'labelAndName + percentage'
+            },
+        pyatspi.ROLE_PUSH_BUTTON: {
+            'unfocused': 'labelAndName + roleName + availability'
+            },
+        pyatspi.ROLE_RADIO_BUTTON: {
+            'focused': 'radioState',
+            'unfocused': 'labelAndName + radioState + roleName + availability'
+            },
+        pyatspi.ROLE_RADIO_MENU_ITEM: {
+            # OpenOffice check menu items currently have a role of "menu item"
+            # rather then "check menu item", so we need to test if one of the
+            # states is CHECKED. If it is, then add that in to the list of
+            # speech utterances. Note that we can't tell if this is a "check
+            # menu item" that is currently unchecked and speak that state.
+            # See Orca bug #433398 for more details.
+            #
+            'focused': 'labelAndName + radioState + roleName + availability',
+            'unfocused': 'labelAndName + radioState + roleName + availability + accelerator'
+            },
+        pyatspi.ROLE_SLIDER: {
+            # Ignore the text on the slider.  See bug 340559
+            # (http://bugzilla.gnome.org/show_bug.cgi?id=340559): the
+            # implementors of the slider support decided to put in a
+            # Unicode left-to-right character as part of the text,
+            # even though that is not painted on the screen.
+            #
+            # In Java, however, there are sliders without a label. In
+            # this case, we'll add to presentation the slider name if
+            # it exists and we haven't found anything yet.
+            #
+            'focused': 'value',
+            'unfocused': 'labelAndName + roleName + value + required + availability'
+            },
+        pyatspi.ROLE_SPIN_BUTTON: {
+            'focused': 'name',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + required'
+            },
+        pyatspi.ROLE_SPLIT_PANE: {
+            'focused': 'value',
+            'unfocused': 'labelAndName + roleName + value + availability'
+            },
+        pyatspi.ROLE_TABLE: {
+            'focused': 'labelAndName + allTextSelection + roleName + availability + noChildren',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability + noChildren'
+            },
+        pyatspi.ROLE_TABLE_CELL: {
+            'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (expandableState and (expandableState + numberOfChildren))',
+            'unfocused': 'tableCellRow'
+            },
+        'REAL_ROLE_TABLE_CELL': {
+            # the real cell information
+            # note that pyatspi.ROLE_TABLE_CELL is used to work out if we need to
+            # read a whole row. It calls REAL_ROLE_TABLE_CELL internally.
+            # maybe it can be done in a cleaner way?
+            #
+            'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (expandableState and (expandableState + numberOfChildren))',
+            'unfocused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + (expandableState and (expandableState + numberOfChildren)) + required'
+            },
+        pyatspi.ROLE_TEAROFF_MENU_ITEM: {
+            'focused': '[]',
+            'unfocused': 'labelAndName + allTextSelection + roleName + availability'
+            },
+        pyatspi.ROLE_TERMINAL: {
+            'focused': 'terminal',
+            'unfocused': 'terminal'
+            },
+        pyatspi.ROLE_TEXT: {
+            'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+            'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+            },
+        pyatspi.ROLE_TOGGLE_BUTTON: {
+            'focused': 'toggleState',
+            'unfocused': 'labelAndName + roleName + toggleState + availability'
+            },
+        pyatspi.ROLE_PARAGRAPH: {
+            'focused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection',
+            'unfocused': 'labelOrName + readOnly + textRole + currentLineText + allTextSelection'
+            },
+        pyatspi.ROLE_EMBEDDED: {
+            'focused': 'embedded',
+            'unfocused': 'embedded'
+            },
+    }
+}
+
+class Formatting(dict):
+
+    def __init__(self, script):
+        dict.__init__(self)
+        self._script = script
+        self.update(copy.deepcopy(formatting))
+
+    def update(self, newDict):
+        for key, val in newDict.iteritems():
+            if self.has_key(key):
+                if isinstance(self[key], dict) and isinstance(val, dict):
+                    self[key].update(val)
+                elif isinstance(self[key], basestring) \
+                     and isinstance(val, basestring):
+                    self[key] = val
+                else:
+                    # exception or such like, we are trying to murge
+                    # incompatible trees.
+                    # throw an exception?
+                    print("an error has occured, cant murge dicts.")
+            else:
+                self[key] = val
+
+    def getPrefix(self, dictType, **args):
+        already_focused = args.get('already_focused', False)
+        if already_focused:
+            focusType = 'focused'
+        else:
+            focusType = 'unfocused'
+        try:
+            prefix = self[dictType]['prefix'][focusType]
+        except:
+            prefix = self[dictType]['prefix']['unfocused']
+        return prefix
+
+    def getSuffix(self, dictType, **args):
+        already_focused = args.get('already_focused', False)
+        if already_focused:
+            focusType = 'focused'
+        else:
+            focusType = 'unfocused'
+        try:
+            suffix = self[dictType]['suffix'][focusType]
+        except:
+            suffix = self[dictType]['suffix']['unfocused']
+        return suffix
+
+    def getFormat(self, dictType, **args):
+        already_focused = args.get('already_focused', False)
+        if already_focused:
+            focusType = 'focused'
+        else:
+            focusType = 'unfocused'
+
+        role = args.get('role', None)
+        try:
+            roleDict = self[dictType][role]
+        except:
+            roleDict = self[dictType]['default']
+
+        try:
+            format = roleDict[focusType]
+        except:
+            try:
+                format = roleDict['unfocused']
+            except:
+                format = self[dictType]['default'][focusType]
+
+        return format
diff --git a/src/orca/liveregions.py b/src/orca/liveregions.py
index 4669993..a318812 100644
--- a/src/orca/liveregions.py
+++ b/src/orca/liveregions.py
@@ -215,7 +215,7 @@ class LiveRegionManager:
                 utts = message['content']
             else:
                 utts = message['labels'] + message['content']
-            speech.speakUtterances(utts)
+            speech.speak(utts)
 
             # set the last live obj to be announced
             self.lastliveobj = obj
@@ -279,7 +279,7 @@ class LiveRegionManager:
             #
             utterances.append(_('setting live region to off'))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def goLastLiveRegion(self):
         """Move the caret to the last announced live region and speak the 
@@ -298,7 +298,7 @@ class LiveRegionManager:
             #
             speech.speak(_('no live message saved'))
         else:
-            speech.speakUtterances(self.msg_cache[-msgnum])
+            speech.speak(self.msg_cache[-msgnum])
 
     def setLivePolitenessOff(self):
         """User toggle to set all live regions to LIVE_OFF or back to their
@@ -384,7 +384,7 @@ class LiveRegionManager:
             # Translators: output the politeness level
             #
             utterances.append(_('politeness level %s') %liveprioritystr)
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
     def matchLiveRegion(self, obj):
         """Predicate used to find a live region"""
@@ -460,7 +460,7 @@ class LiveRegionManager:
             speech.stop()
             # Note: we would like to use a different ACSS for alerts.  This work
             # should be done as part of bug #412656.
-            speech.speakUtterances(utts)
+            speech.speak(utts)
             return None
         else:
             return {'content':content, 'labels':labels}
diff --git a/src/orca/mouse_review.py b/src/orca/mouse_review.py
index 4f7c83a..45ac68a 100644
--- a/src/orca/mouse_review.py
+++ b/src/orca/mouse_review.py
@@ -265,10 +265,9 @@ class MouseReviewer:
                 # display.
                 braille.displayMessage(obj)
             else:
-                speech.speakUtterances(
+                speech.speak(
                     self._currentMouseOver.script.speechGenerator.getSpeech(
-                            obj,
-                            False))
+                        obj))
                 self._currentMouseOver.script.updateBraille(obj)
 
     def _getZOrder(self, frame_name):
diff --git a/src/orca/orca-setup.glade b/src/orca/orca-setup.glade
index e00c390..edae6e3 100644
--- a/src/orca/orca-setup.glade
+++ b/src/orca/orca-setup.glade
@@ -1299,7 +1299,7 @@ Hyperlink</property>
 				      <property name="update_policy">GTK_UPDATE_ALWAYS</property>
 				      <property name="snap_to_ticks">False</property>
 				      <property name="wrap">False</property>
-				      <property name="adjustment">10 1 9999 1 10 0</property>
+				      <property name="adjustment">10 0 9999 1 10 0</property>
 				      <accessibility>
 				        <atkrelation target="speakProgressBarUnitsLabel" type="labelled-by"/>
 				        <atkrelation target="speakProgressBarLabel" type="labelled-by"/>
diff --git a/src/orca/script.py b/src/orca/script.py
index 563e09d..6b67418 100644
--- a/src/orca/script.py
+++ b/src/orca/script.py
@@ -42,10 +42,11 @@ __license__   = "LGPL"
 import braillegenerator
 import debug
 import flat_review
+import formatting
 import keybindings
 import orca_state
 import settings
-import speechgenerator
+import speech_generator
 import structural_navigation
 import where_am_I
 import bookmarks
@@ -86,6 +87,7 @@ class Script:
         self.brailleBindings = self.getBrailleBindings()
         self.app_pronunciation_dict = self.getPronunciations()
 
+        self.formatting = self.getFormatting()
         self.brailleGenerator = self.getBrailleGenerator()
         self.speechGenerator = self.getSpeechGenerator()
         self.whereAmI = self.getWhereAmI()
@@ -178,6 +180,10 @@ class Script:
                 for command, handler in self.brailleBindings.iteritems()
                 if inputEventHandler == handler]
 
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return formatting.Formatting(self)
+
     def getBrailleGenerator(self):
         """Returns the braille generator for this script.
         """
@@ -186,7 +192,7 @@ class Script:
     def getSpeechGenerator(self):
         """Returns the speech generator for this script.
         """
-        return speechgenerator.SpeechGenerator(self)
+        return speech_generator.SpeechGenerator(self)
 
     def getTutorialGenerator(self):
         """Returns the tutorial generator for this script.
diff --git a/src/orca/scripts/apps/Thunderbird/script.py b/src/orca/scripts/apps/Thunderbird/script.py
index 982eb33..dc76e4c 100644
--- a/src/orca/scripts/apps/Thunderbird/script.py
+++ b/src/orca/scripts/apps/Thunderbird/script.py
@@ -23,7 +23,7 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2004-2008 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import gtk
@@ -549,7 +549,7 @@ class Script(Gecko.Script):
                 #
                 text = _("%s panel") % parent.name
                 utterances.append(text)
-                speech.speakUtterances(utterances)
+                speech.speak(utterances)
         else:
             grandparent = parent.parent
             if grandparent \
@@ -566,7 +566,7 @@ class Script(Gecko.Script):
                     #
                     text = _("%s panel") % grandparent.name
                     utterances.append(text)
-                    speech.speakUtterances(utterances)
+                    speech.speak(utterances)
 
     def _presentMessage(self, documentFrame):
         """Presents the first line of the message, or the entire message,
diff --git a/src/orca/scripts/apps/Thunderbird/speech_generator.py b/src/orca/scripts/apps/Thunderbird/speech_generator.py
index cf1e5f0..8ad4cd6 100644
--- a/src/orca/scripts/apps/Thunderbird/speech_generator.py
+++ b/src/orca/scripts/apps/Thunderbird/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2004-2008 Sun Microsystems Inc.
+# Copyright 2004-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -23,12 +23,11 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
 
-import orca.debug as debug
 import orca.scripts.toolkits.Gecko as Gecko
 
 from orca.orca_i18n import _
@@ -43,51 +42,29 @@ class SpeechGenerator(Gecko.SpeechGenerator):
     """Provides a speech generator specific to Thunderbird.
     """
 
-    def __init__(self, script):
-        # Set the debug level for all the methods in this script.
-        #
-        self.debugLevel = debug.LEVEL_FINEST
+    # pylint: disable-msg=W0142
 
-        self._debug("__init__")
+    def __init__(self, script):
         Gecko.SpeechGenerator.__init__(self, script)
 
-    def _debug(self, msg):
-        """ Convenience method for printing debug messages
-        """
-        debug.println(self.debugLevel, "Thunderbird.SpeechGenerator: "+msg)
-
-    def _getSpeechForAlert(self, obj, already_focused):
-        """Gets the title of the dialog and the contents of labels inside the
-        dialog that are not associated with any other objects.
-
-        Arguments:
-        - obj: the Accessible dialog
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances be spoken.
+    def _getUnrelatedLabels(self, obj, **args):
+        """Finds all labels not in a label for or labelled by relation.
+        If this is the spell checking dialog, then there are no
+        unrelated labels.  See bug #535192 for more details.
         """
+        result = []
 
-        # If this is the spell checking dialog, then just return the title
-        # of the dialog. See bug #535192 for more details.
+        # Translators: this is what the name of the spell checking
+        # dialog in Thunderbird begins with. The translated form
+        # has to match what Thunderbird is using.  We hate keying
+        # off stuff like this, but we're forced to do so in this case.
         #
-        rolesList = [pyatspi.ROLE_DIALOG, \
-                     pyatspi.ROLE_APPLICATION]
-        if self._script.isDesiredFocusedItem(obj, rolesList):
-            # Translators: this is what the name of the spell checking
-            # dialog in Thunderbird begins with. The translated form
-            # has to match what Thunderbird is using.  We hate keying
-            # off stuff like this, but we're forced to do so in this case.
-            #
-            if obj.name.startswith(_("Check Spelling")):
-                utterances = []
-                utterances.extend(self._getSpeechForObjectName(obj))
-
-                self._debugGenerator("Thunderbird: _getSpeechForAlert",
-                                     obj,
-                                     already_focused,
-                                     utterances)
-
-                return utterances
-
-        return Gecko.SpeechGenerator._getSpeechForAlert(self, obj,
-                                                        already_focused)
+        if obj.name.startswith(_("Check Spelling")) \
+           and self._script.isDesiredFocusedItem(
+                   obj, [pyatspi.ROLE_DIALOG,
+                         pyatspi.ROLE_APPLICATION]):
+            pass
+        else:
+            result.extend(Gecko.SpeechGenerator._getUnrelatedLabels(
+                              self, obj, **args))
+        return result
diff --git a/src/orca/scripts/apps/acroread.py b/src/orca/scripts/apps/acroread.py
index df5fc0b..94ae5b5 100644
--- a/src/orca/scripts/apps/acroread.py
+++ b/src/orca/scripts/apps/acroread.py
@@ -436,8 +436,8 @@ class Script(default.Script):
                 return
 
             utterances = \
-                 self.speechGenerator.getSpeech(newLocusOfFocus, False)
-            speech.speakUtterances(utterances)
+                 self.speechGenerator.getSpeech(newLocusOfFocus)
+            speech.speak(utterances)
             brailleRegions = \
                  self.brailleGenerator.getBrailleRegions(newLocusOfFocus)
             braille.displayRegions(brailleRegions)
@@ -465,11 +465,11 @@ class Script(default.Script):
             # verboseness: reporting the drawing area(s) in which this link
             # is contained, speaking the periods in a table of contents, etc.
             #
-            utterances = self.speechGenerator.getSpeech(newLocusOfFocus, False)
+            utterances = self.speechGenerator.getSpeech(newLocusOfFocus)
             adjustedUtterances = []
             for utterance in utterances:
                 adjustedUtterances.append(self.adjustForRepeats(utterance))
-            speech.speakUtterances(adjustedUtterances)
+            speech.speak(adjustedUtterances)
             brailleRegions = \
                      self.brailleGenerator.getBrailleRegions(newLocusOfFocus)
             braille.displayRegions(brailleRegions)
@@ -549,8 +549,8 @@ class Script(default.Script):
                 # Try to minimize chattiness in the Search panel
                 #
                 utterances = \
-                     self.speechGenerator.getSpeech(event.source, False)
-                speech.speakUtterances(utterances)
+                     self.speechGenerator.getSpeech(event.source)
+                speech.speak(utterances)
                 brailleRegions = \
                      self.brailleGenerator.getBrailleRegions(event.source)
                 braille.displayRegions(brailleRegions)
diff --git a/src/orca/scripts/apps/evolution/Makefile.am b/src/orca/scripts/apps/evolution/Makefile.am
index 9a00a0b..1ca5519 100644
--- a/src/orca/scripts/apps/evolution/Makefile.am
+++ b/src/orca/scripts/apps/evolution/Makefile.am
@@ -1,10 +1,11 @@
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
-	__init__.py \
-	script.py \
-	speech_generator.py \
-	where_am_i.py
+    __init__.py \
+    formatting.py \
+    script.py \
+    speech_generator.py \
+    where_am_i.py
 
 orca_pythondir=$(pyexecdir)/orca/scripts/apps/evolution
 
diff --git a/src/orca/scripts/apps/evolution/formatting.py b/src/orca/scripts/apps/evolution/formatting.py
new file mode 100644
index 0000000..cff931e
--- /dev/null
+++ b/src/orca/scripts/apps/evolution/formatting.py
@@ -0,0 +1,50 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for evolution."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+# pylint: disable-msg=C0301
+
+import copy
+
+import orca.formatting
+
+formatting = {
+    'speech': {
+        'ALTERNATIVE_REAL_ROLE_TABLE_CELL': {
+            # the real cell information
+            # note that pyatspi.ROLE_TABLE_CELL is used to work out if we need to
+            # read a whole row. It calls REAL_ROLE_TABLE_CELL internally.
+            #
+            'focused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + (expandableState and expandableState ) + required',
+            'unfocused': '(tableCell2ChildLabel + tableCell2ChildToggle) or cellCheckedState + (realActiveDescendantDisplayedText or imageDescription + image) + (expandableState and expandableState ) + required',
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
diff --git a/src/orca/scripts/apps/evolution/script.py b/src/orca/scripts/apps/evolution/script.py
index b78bb4e..abada76 100644
--- a/src/orca/scripts/apps/evolution/script.py
+++ b/src/orca/scripts/apps/evolution/script.py
@@ -43,6 +43,7 @@ from orca.orca_i18n import _ # for gettext support
 
 from where_am_i import WhereAmI
 from speech_generator import SpeechGenerator
+from formatting import Formatting
 ########################################################################
 #                                                                      #
 # The Evolution script class.                                          #
@@ -145,6 +146,10 @@ class Script(default.Script):
 
         return WhereAmI(self)
 
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
+
     def setupInputEventHandlers(self):
         """Defines InputEventHandler fields for this script that can be
         called by the key and braille bindings. In this particular case,
@@ -283,9 +288,9 @@ class Script(default.Script):
                                                    getState().contains( \
                                        pyatspi.STATE_SENSITIVE)):
                                     self.updateBraille(orca_state.locusOfFocus)
-                                    speech.speakUtterances(
-                                        self.speechGenerator.getSpeech( \
-                                            orca_state.locusOfFocus, False))
+                                    speech.speak(
+                                        self.speechGenerator.getSpeech(
+                                            orca_state.locusOfFocus))
             except NotImplementedError:
                 pass
 
@@ -337,8 +342,8 @@ class Script(default.Script):
 
         savedSpeechVerbosityLevel = settings.speechVerbosityLevel
         settings.speechVerbosityLevel = settings.VERBOSITY_LEVEL_BRIEF
-        utterances = speechGen.getSpeech(tab, False)
-        speech.speakUtterances(utterances)
+        utterances = speechGen.getSpeech(tab)
+        speech.speak(utterances)
         settings.speechVerbosityLevel = savedSpeechVerbosityLevel
 
         braille.displayRegions(brailleGen.getBrailleRegions(tab))
@@ -771,7 +776,7 @@ class Script(default.Script):
                         utterances.append(string)
 
                 braille.displayRegions([regions, regions[0]])
-                speech.speakUtterances(utterances)
+                speech.speak(utterances)
                 return
 
         # 3) Mail view: message header list
@@ -942,7 +947,7 @@ class Script(default.Script):
                             settings.speechVerbosityLevel = \
                                 settings.VERBOSITY_LEVEL_BRIEF
 
-                            utterances = speechGen.getSpeech(header, False)
+                            utterances = speechGen.getSpeech(header)
                             [headerRegions, focusedRegion] = \
                                          brailleGen.getBrailleRegions(header)
                             brailleRegions.extend(headerRegions)
@@ -951,7 +956,7 @@ class Script(default.Script):
                             if column == i:
                                 cellWithFocus = focusedRegion
                             if speakAll or (column == i):
-                                speech.speakUtterances(utterances)
+                                speech.speak(utterances)
 
                         # Speak/braille the table cell.
                         #
@@ -968,7 +973,7 @@ class Script(default.Script):
                                 settings.VERBOSITY_LEVEL_BRIEF
                         settings.speechVerbosityLevel = \
                             savedSpeechVerbosityLevel
-                        utterances = speechGen.getSpeech(cell, False)
+                        utterances = speechGen.getSpeech(cell)
                         [cellRegions, focusedRegion] = \
                                            brailleGen.getBrailleRegions(cell)
 
@@ -1020,7 +1025,7 @@ class Script(default.Script):
                             cellWithFocus = focusedRegion
 
                         if speakAll or (column == i):
-                            speech.speakUtterances(utterances)
+                            speech.speak(utterances)
 
             if brailleRegions != []:
                 braille.displayRegions([brailleRegions, cellWithFocus])
@@ -1059,10 +1064,10 @@ class Script(default.Script):
                           + "day view: tabbing to day with appts.")
 
             parent = event.source.parent
-            utterances = speechGen.getSpeech(parent, False)
+            utterances = speechGen.getSpeech(parent)
             [brailleRegions, focusedRegion] = \
                     brailleGen.getBrailleRegions(parent)
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
             apptExtents = event.source.queryComponent().getExtents(0)
 
@@ -1075,12 +1080,11 @@ class Script(default.Script):
                         appt = childTable.getAccessibleAt(row, 0)
                         extents = appt.queryComponent().getExtents(0)
                         if extents.y == apptExtents.y:
-                            utterances = speechGen.getSpeech(event.source, \
-                                                             False)
+                            utterances = speechGen.getSpeech(event.source)
                             [apptRegions, focusedRegion] = \
                                 brailleGen.getBrailleRegions(event.source)
                             brailleRegions.extend(apptRegions)
-                            speech.speakUtterances(utterances)
+                            speech.speak(utterances)
 
                             startTime = 'Start time ' + \
                                 self.getTimeForCalRow(j, noRows)
@@ -1137,11 +1141,11 @@ class Script(default.Script):
                     apptExtents = child.queryComponent().getExtents(0)
 
                     if extents.y == apptExtents.y:
-                        utterances = speechGen.getSpeech(child, False)
+                        utterances = speechGen.getSpeech(child)
                         [apptRegions, focusedRegion] = \
                             brailleGen.getBrailleRegions(child)
                         brailleRegions.extend(apptRegions)
-                        speech.speakUtterances(utterances)
+                        speech.speak(utterances)
 
                         startTime = 'Start time ' + \
                             self.getTimeForCalRow(index, noRows)
diff --git a/src/orca/scripts/apps/evolution/speech_generator.py b/src/orca/scripts/apps/evolution/speech_generator.py
index aa0bbb1..0d71bee 100644
--- a/src/orca/scripts/apps/evolution/speech_generator.py
+++ b/src/orca/scripts/apps/evolution/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,38 +22,28 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
 
-import orca.speechgenerator as speechgenerator
+import orca.speech_generator as speech_generator
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
-    """Overrides _getSpeechForTableCell so that, if this is an expanded 
+class SpeechGenerator(speech_generator.SpeechGenerator):
+    """Overrides _getSpeechForTableCell so that, if this is an expanded
        table cell,  we can strip off the "0 items".
     """
 
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def _getSpeechForTableCell(self, obj, already_focused):
-        """Get the speech utterances for a single table cell
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
+    # pylint: disable-msg=W0142
 
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = speechgenerator.SpeechGenerator.\
-                      _getSpeechForTableCell(self, obj, already_focused)
+    def __init__(self, script):
+        speech_generator.SpeechGenerator.__init__(self, script)
 
+    def _getRealTableCell(self, obj, **args):
         # Check that we are in a table cell in the mail message header list.
-        # If we are and this table cell has an expanded state, and the first
-        # token of the last utterances is "0", then strip off that last 
-        # utterance ("0 items"). See bug #432308 for more details.
+        # If we are and this table cell has an expanded state, then
+        # dont speak the number of items.
+        # See bug #432308 for more details.
         #
         rolesList = [pyatspi.ROLE_TABLE_CELL, \
                      pyatspi.ROLE_TREE_TABLE, \
@@ -62,8 +52,10 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
             state = obj.getState()
             if state and state.contains(pyatspi.STATE_EXPANDABLE):
                 if state.contains(pyatspi.STATE_EXPANDED):
-                    tokens = utterances[-1].split()
-                    if tokens[0] == "0":
-                        utterances = utterances[0:-1]
-
-        return utterances
+                    oldRole = self._overrideRole(
+                        'ALTERNATIVE_REAL_ROLE_TABLE_CELL', args)
+                    result = self.getSpeech(obj, **args)
+                    self._restoreRole(oldRole, args)
+                    return result
+        return speech_generator.SpeechGenerator._getRealTableCell(
+            self, obj, **args)
diff --git a/src/orca/scripts/apps/gcalctool/speech_generator.py b/src/orca/scripts/apps/gcalctool/speech_generator.py
index 9aaf553..ea2fe5f 100644
--- a/src/orca/scripts/apps/gcalctool/speech_generator.py
+++ b/src/orca/scripts/apps/gcalctool/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2004-2008 Sun Microsystems Inc.
+# Copyright 2004-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,27 +22,27 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
-import orca.speechgenerator as speechgenerator
+import orca.speech_generator as speech_generator
 import pyatspi
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
+class SpeechGenerator(speech_generator.SpeechGenerator):
     """Overrides _getSpeechForPushButton to handle 'unspeakable'
     button labels displayed on the screen.
     """
     def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
+        speech_generator.SpeechGenerator.__init__(self, script)
 
-    def _getSpeechForObjectName(self, obj):
+    def _getName(self, obj, **args):
         """Gives preference to the object name versus what is being
         displayed on the screen.  This helps accomodate the naming
         hints being given to us by gcalctool for it's mathematical
         operator buttons."""
 
         if obj.getRole() != pyatspi.ROLE_PUSH_BUTTON:
-            return speechgenerator.SpeechGenerator._getSpeechForObjectName(\
+            return speech_generator.SpeechGenerator._getName(\
                 self, obj)
 
         if obj.name:
diff --git a/src/orca/scripts/apps/gcalctool/where_am_i.py b/src/orca/scripts/apps/gcalctool/where_am_i.py
index 10a6e96..45bbfb9 100644
--- a/src/orca/scripts/apps/gcalctool/where_am_i.py
+++ b/src/orca/scripts/apps/gcalctool/where_am_i.py
@@ -46,4 +46,4 @@ class WhereAmI(where_am_I.WhereAmI):
         utterances = []
         text = self.getObjLabelAndName(self._statusBar)
         utterances.append(text)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
diff --git a/src/orca/scripts/apps/gedit/script.py b/src/orca/scripts/apps/gedit/script.py
index a889ff4..6483bad 100644
--- a/src/orca/scripts/apps/gedit/script.py
+++ b/src/orca/scripts/apps/gedit/script.py
@@ -427,7 +427,7 @@ class Script(default.Script):
             line.addRegion(braille.Region(" " + label1))
             line.addRegion(braille.Region(" " + label2))
 
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
             braille.refresh()
 
     # This method tries to detect and handle the following cases:
@@ -569,8 +569,9 @@ class Script(default.Script):
                 # finding something.
                 #
                 speech.speak(_("Phrase found."))
-                utterances = self.speechGenerator.getSpeech(event.source, True)
-                speech.speakUtterances(utterances)
+                utterances = self.speechGenerator.getSpeech(
+                    event.source, already_focused=True)
+                speech.speak(utterances)
 
         # If Ctrl+G was used to repeat a find command, speak the line that
         # the caret moved to.
diff --git a/src/orca/scripts/apps/gnome-system-monitor.py b/src/orca/scripts/apps/gnome-system-monitor.py
index 6cfa173..fc8922d 100644
--- a/src/orca/scripts/apps/gnome-system-monitor.py
+++ b/src/orca/scripts/apps/gnome-system-monitor.py
@@ -94,5 +94,5 @@ class Script(default.Script):
                         line.addRegion(braille.Region(" " + label.name))
                         utterances.append(label.name)
 
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
             braille.refresh()
diff --git a/src/orca/scripts/apps/gnome-terminal.py b/src/orca/scripts/apps/gnome-terminal.py
index 3e35a38..8b905d0 100644
--- a/src/orca/scripts/apps/gnome-terminal.py
+++ b/src/orca/scripts/apps/gnome-terminal.py
@@ -100,8 +100,8 @@ class Script(default.Script):
                pageTab.getRole() == pyatspi.ROLE_PAGE_TAB and \
                pageTab.getState().contains(pyatspi.STATE_SENSITIVE):
                 self.updateBraille(newLocusOfFocus)
-                utterances = self.speechGenerator.getSpeech(pageTab, False)
-                speech.speakUtterances(utterances)
+                utterances = self.speechGenerator.getSpeech(pageTab)
+                speech.speak(utterances)
 
         default.Script.locusOfFocusChanged(self, event, 
                                            oldLocusOfFocus, newLocusOfFocus)
diff --git a/src/orca/scripts/apps/gnome-window-properties/Makefile.am b/src/orca/scripts/apps/gnome-window-properties/Makefile.am
index c19b657..1e8a46c 100644
--- a/src/orca/scripts/apps/gnome-window-properties/Makefile.am
+++ b/src/orca/scripts/apps/gnome-window-properties/Makefile.am
@@ -1,9 +1,10 @@
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
-	__init__.py \
-	script.py \
-	speech_generator.py
+    __init__.py \
+    formatting.py \
+    script.py
+
 
 orca_pythondir=$(pyexecdir)/orca/scripts/apps/gnome-window-properties
 
diff --git a/src/orca/scripts/apps/gnome-window-properties/formatting.py b/src/orca/scripts/apps/gnome-window-properties/formatting.py
new file mode 100644
index 0000000..5538aee
--- /dev/null
+++ b/src/orca/scripts/apps/gnome-window-properties/formatting.py
@@ -0,0 +1,45 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for gnome-window-properties."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import copy
+
+import pyatspi
+
+import orca.formatting
+
+formatting = {
+    'speech': {
+        pyatspi.ROLE_ALERT: {
+            'unfocused': 'labelAndName + roleName'
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
diff --git a/src/orca/scripts/apps/gnome-window-properties/script.py b/src/orca/scripts/apps/gnome-window-properties/script.py
index b892a46..531aa4a 100644
--- a/src/orca/scripts/apps/gnome-window-properties/script.py
+++ b/src/orca/scripts/apps/gnome-window-properties/script.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2006-2008 Sun Microsystems Inc.
+# Copyright 2006-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,12 +22,12 @@
 __id__ = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import orca.default as default
 
-from speech_generator import SpeechGenerator
+from formatting import Formatting
 
 ########################################################################
 #                                                                      #
@@ -35,7 +35,6 @@ from speech_generator import SpeechGenerator
 #                                                                      #
 ########################################################################
 
-
 class Script(default.Script):
 
     def __init__(self, app):
@@ -46,7 +45,6 @@ class Script(default.Script):
         """
         default.Script.__init__(self, app)
 
-    def getSpeechGenerator(self):
-        """Returns the speech generator for this script.
-        """
-        return SpeechGenerator(self)
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
diff --git a/src/orca/scripts/apps/gnome-window-properties/speech_generator.py b/src/orca/scripts/apps/gnome-window-properties/speech_generator.py
deleted file mode 100644
index 65bb180..0000000
--- a/src/orca/scripts/apps/gnome-window-properties/speech_generator.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Orca
-#
-# Copyright 2006-2008 Sun Microsystems Inc.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA  02110-1301 USA.
-
-"""Custom script for gnome-window-properties."""
-
-__id__ = "$Id$"
-__version__   = "$Revision$"
-__date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
-__license__   = "LGPL"
-
-import orca.speechgenerator as speechgenerator
-
-class SpeechGenerator(speechgenerator.SpeechGenerator):
-    """Overrides _getSpeechForFrame so as to avoid digging into the
-    gedit hierarchy and tickling a bug in gedit.
-    """
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def _getSpeechForAlert(self, obj, already_focused):
-        """Gets the title of the dialog.  Do NOT get the contents
-        of labels inside the dialog that are not associated with any
-        other objects.
-
-        Arguments:
-        - obj: the Accessible dialog
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances be spoken.
-        """
-
-        utterances = []
-        utterances.extend(self._getSpeechForObjectLabel(obj))
-        utterances.extend(self._getSpeechForObjectName(obj))
-        utterances.extend(self.getSpeechForObjectRole(obj))
-
-        self._debugGenerator("gnome-window-properties._getSpeechForAlert",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
diff --git a/src/orca/scripts/apps/liferea.py b/src/orca/scripts/apps/liferea.py
index 876b117..32a0a05 100644
--- a/src/orca/scripts/apps/liferea.py
+++ b/src/orca/scripts/apps/liferea.py
@@ -119,11 +119,11 @@ class Script(default.Script):
             # Here we extend the utterances with the speech generator for 
             # the object with focus (the push button).
             #
-            utterances.extend(speechGen.getSpeech(event.source, False))
+            utterances.extend(speechGen.getSpeech(event.source))
 
             # Finally we speak/braille the utterances/regions.
             #
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
            
             regions = brailleGen.getBrailleRegions(event.source)
             regions[0].insert(0, braille.Region(utterances[0] + " "))
diff --git a/src/orca/scripts/apps/pidgin/speech_generator.py b/src/orca/scripts/apps/pidgin/speech_generator.py
index 73da585..6c91709 100644
--- a/src/orca/scripts/apps/pidgin/speech_generator.py
+++ b/src/orca/scripts/apps/pidgin/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2004-2008 Sun Microsystems Inc.
+# Copyright 2004-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -17,29 +17,13 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
-"""Custom script for gaim.  This provides the ability for Orca to
-monitor both the IM input and IM output text areas at the same time.
-
-The following script specific key sequences are supported:
-
-  Insert-h      -  Toggle whether we prefix chat room messages with
-                   the name of the chat room.
-  Insert-[1-9]  -  Speak and braille a previous chat room message.
-"""
-
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
-import pyatspi
-
-import orca.settings as settings
-import orca.speechgenerator as speechgenerator
-
-from orca.orca_i18n import _
-from orca.orca_i18n import ngettext  # for ngettext support
+import orca.speech_generator as speech_generator
 
 ########################################################################
 #                                                                      #
@@ -47,72 +31,62 @@ from orca.orca_i18n import ngettext  # for ngettext support
 #                                                                      #
 ########################################################################
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
+class SpeechGenerator(speech_generator.SpeechGenerator):
     """Overrides _getSpeechForTableCell() so that we can provide access
     to the expanded/collapsed state and node count for the buddy list.
     """
 
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def _getSpeechForTableCell(self, obj, already_focused):
-        """Get the speech utterances for a single table cell
-
-        Arguments:
-        - obj: the table cell
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
+    # pylint: disable-msg=W0142
 
-        utterances = speechgenerator.SpeechGenerator._getSpeechForTableCell( \
-            self, obj, already_focused)
-
-        if not self._script.isInBuddyList(obj):
-            return utterances
-
-        # The Pidgin buddy list consists of two columns. The column which
-        # is set as the expander column and which also contains the node
-        # relationship is hidden.  Hidden columns are not included among
-        # a table's columns.  The hidden object of interest seems to always
-        # immediately precede the visible object.
-        #
-        expanderCell = obj.parent[obj.getIndexInParent() - 1]
-        if not expanderCell:
-            return utterances
-
-        state = expanderCell.getState()
-        if state.contains(pyatspi.STATE_EXPANDABLE):
-            if state.contains(pyatspi.STATE_EXPANDED):
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("expanded"))
-                childNodes = self._script.getChildNodes(expanderCell)
-                children = len(childNodes)
-
-                if not children \
-                   or (settings.speechVerbosityLevel == \
-                       settings.VERBOSITY_LEVEL_VERBOSE):
-                    # Translators: this is the number of items in a layered
-                    # pane or table.
-                    #
-                    itemString = ngettext("%d item",
-                                          "%d items",
-                                          children) % children
-                    utterances.append(itemString)
+    def __init__(self, script):
+        speech_generator.SpeechGenerator.__init__(self, script)
+
+    def _getExpandableState(self, obj, **args):
+        result = []
+        if self._script.isInBuddyList(obj):
+            # The Pidgin buddy list consists of two columns. The
+            # column which is set as the expander column and which
+            # also contains the node relationship is hidden.  Hidden
+            # columns are not included among a table's columns.  The
+            # hidden object of interest seems to always immediately
+            # precede the visible object.
+            #
+            expanderCell = obj.parent[obj.getIndexInParent() - 1]
+            if expanderCell:
+                result.extend(
+                    speech_generator.SpeechGenerator._getExpandableState(
+                        self, expanderCell, **args))
             else:
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("collapsed"))
-
-        self._debugGenerator("gaim._getSpeechForTableCell",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
+                result.extend(
+                    speech_generator.SpeechGenerator._getExpandableState(
+                        self, obj, **args))
+        else:
+            result.extend(
+                speech_generator.SpeechGenerator._getExpandableState(
+                    self, obj, **args))
+        return result
+
+    def _getNumberOfChildren(self, obj, **args):
+        result = []
+        if self._script.isInBuddyList(obj):
+            # The Pidgin buddy list consists of two columns. The
+            # column which is set as the expander column and which
+            # also contains the node relationship is hidden.  Hidden
+            # columns are not included among a table's columns.  The
+            # hidden object of interest seems to always immediately
+            # precede the visible object.
+            #
+            expanderCell = obj.parent[obj.getIndexInParent() - 1]
+            if expanderCell:
+                result.extend(
+                    speech_generator.SpeechGenerator._getNumberOfChildren(
+                        self, expanderCell, **args))
+            else:
+                result.extend(
+                    speech_generator.SpeechGenerator._getNumberOfChildren(
+                        self, obj, **args))
+        else:
+            result.extend(
+                speech_generator.SpeechGenerator._getNumberOfChildren(
+                    self, obj, **args))
+        return result
diff --git a/src/orca/scripts/apps/pidgin/where_am_i.py b/src/orca/scripts/apps/pidgin/where_am_i.py
index f3de065..9e7008f 100644
--- a/src/orca/scripts/apps/pidgin/where_am_i.py
+++ b/src/orca/scripts/apps/pidgin/where_am_i.py
@@ -88,7 +88,7 @@ class WhereAmI(where_am_I.WhereAmI):
         utterances.append(text)
         debug.println(self._debugLevel, "first table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
         utterances = []
         if doubleClick:
@@ -99,14 +99,14 @@ class WhereAmI(where_am_I.WhereAmI):
             #
             text = _("row %d of %d") % ((row+1), table.nRows)
             utterances.append(text)
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
         # Speak the current row
         #
         utterances = self._getTableRow(obj)
         debug.println(self._debugLevel, "second table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
         # Speak the remaining items.
         #
@@ -159,4 +159,4 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel, "third table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
diff --git a/src/orca/scripts/apps/planner/Makefile.am b/src/orca/scripts/apps/planner/Makefile.am
index f5da4c1..a9365cd 100644
--- a/src/orca/scripts/apps/planner/Makefile.am
+++ b/src/orca/scripts/apps/planner/Makefile.am
@@ -1,10 +1,10 @@
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
-	__init__.py \
-	braille_generator.py \
-	script.py \
-	speech_generator.py
+    __init__.py \
+    braille_generator.py \
+    script.py \
+    speech_generator.py
 
 orca_pythondir=$(pyexecdir)/orca/scripts/apps/planner
 
diff --git a/src/orca/scripts/apps/planner/script.py b/src/orca/scripts/apps/planner/script.py
index a837129..decea2d 100644
--- a/src/orca/scripts/apps/planner/script.py
+++ b/src/orca/scripts/apps/planner/script.py
@@ -27,8 +27,8 @@ __license__   = "LGPL"
 
 import orca.default as default
 
-from speech_generator import SpeechGenerator
 from braille_generator import BrailleGenerator
+from speech_generator import SpeechGenerator
 
 ########################################################################
 #                                                                      #
@@ -46,10 +46,6 @@ class Script(default.Script):
         """
         default.Script.__init__(self, app)
 
-    # This method tries to detect and handle the following cases:
-    # 1) Toolbar: the last toggle button to show 'more options'
-    # 2) Main window: one of the four graphic toggle buttons.
-    #
     def getBrailleGenerator(self):
         return BrailleGenerator(self)
 
diff --git a/src/orca/scripts/apps/planner/speech_generator.py b/src/orca/scripts/apps/planner/speech_generator.py
index 7a164cf..0f31c6a 100644
--- a/src/orca/scripts/apps/planner/speech_generator.py
+++ b/src/orca/scripts/apps/planner/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2006-2008 Sun Microsystems Inc.
+# Copyright 2006-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,56 +22,49 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2006-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2006-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
-import orca.speechgenerator as speechgenerator
 import pyatspi
 
-from orca.orca_i18n import _ # for gettext support
+import orca.speech_generator as speech_generator
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
+from orca.orca_i18n import _         # for gettext support
 
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    # We make this to appropiately present ribbon's toggle button in a
-    # toolbar used to display in a menu those options that doesn fill
-    # in toolbar when the application is resized.
-    #
-    # Also for each one of the grphics buttons in the main window
-    #
-    def _getSpeechForToggleButton(self, obj, already_focused):
-        utterances = []
-        tmp = []
+class SpeechGenerator(speech_generator.SpeechGenerator):
 
-        # Application should implement an accessible name in this
-        # component, but until this is made We speech/braille "display
-        # more options" when the focus is in one of these toggle
-        # buttons.
-        #
+    # pylint: disable-msg=W0142
 
-        roleList = [pyatspi.ROLE_TOGGLE_BUTTON, \
-                    pyatspi.ROLE_TOOL_BAR]
+    def __init__(self, script):
+        speech_generator.SpeechGenerator.__init__(self, script)
 
-        if self._script.isDesiredFocusedItem(obj, roleList) and not obj.name:
-            if not already_focused:
-                tmp.append(_("Display more options"))
-                tmp.extend(self._getDefaultSpeech(obj, already_focused))
+    def _getLabelAndName(self, obj, **args):
+        """Gets the label and the name if the name is different from the label.
+        """
+        result = []
 
-                if obj.getState().contains(pyatspi.STATE_CHECKED):
-                    tmp.append(_("pressed"))
-                else:
-                    tmp.append(_("not pressed"))
+        # This is the black triangle at the far right of the toolbar.
+        #
+        handleRibbonButton = \
+            obj and not obj.name \
+            and obj.getRole() == pyatspi.ROLE_TOGGLE_BUTTON \
+            and obj.parent.getRole() == pyatspi.ROLE_TOOL_BAR
 
-                utterances.extend(tmp)
-                utterances.extend(self._getSpeechForObjectAvailability(obj))
-            else:
-                if obj.getState().contains(pyatspi.STATE_CHECKED):
-                    utterances.append(_("pressed"))
-                else:
-                    utterances.append(_("not pressed"))
+        # This is one of the Gantt, Tasks, Resources, etc., buttons on the
+        # left hand side of the main window.
+        #
+        handleTabButton = \
+            obj and not obj.name \
+            and obj.getRole() == pyatspi.ROLE_TOGGLE_BUTTON \
+            and obj.parent.getRole() == pyatspi.ROLE_FILLER \
+            and len(obj.parent) == 2
 
-            return utterances
+        if handleRibbonButton:
+            result.append(_("Display more options"))
+        elif handleTabButton:
+            result.append(self._script.getDisplayedText(obj.parent[1]))
+        else:
+            result.append(speech_generator.SpeechGenerator._getLabelAndName(
+                self, obj, **args))
 
-        return self._getSpeechForLabel(obj, already_focused)
+        return result
diff --git a/src/orca/scripts/apps/rhythmbox/Makefile.am b/src/orca/scripts/apps/rhythmbox/Makefile.am
index 37f07a7..9bbca3e 100644
--- a/src/orca/scripts/apps/rhythmbox/Makefile.am
+++ b/src/orca/scripts/apps/rhythmbox/Makefile.am
@@ -3,6 +3,7 @@ orca_pathdir=$(pyexecdir)
 orca_python_PYTHON = \
 	__init__.py \
 	braille_generator.py \
+	formatting.py \
 	script.py \
 	speech_generator.py
 
diff --git a/src/orca/scripts/apps/rhythmbox/formatting.py b/src/orca/scripts/apps/rhythmbox/formatting.py
new file mode 100644
index 0000000..c3e82d7
--- /dev/null
+++ b/src/orca/scripts/apps/rhythmbox/formatting.py
@@ -0,0 +1,52 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for rhythmbox."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import copy
+
+import pyatspi
+
+import orca.formatting
+
+formatting = {
+    'speech': {
+        # When the rating widget changes values, it emits an accessible
+        # name changed event. Because it is of ROLE_UNKNOWN, the default
+        # speech_generator's _getDefaultSpeech handles it. And because
+        # the widget is already focused, it doesn't speak anything. We
+        # want to speak the widget's name as it contains the number of
+        # stars being displayed.
+        #
+        pyatspi.ROLE_UNKNOWN: {
+            'focused': 'labelAndName'
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
diff --git a/src/orca/scripts/apps/rhythmbox/script.py b/src/orca/scripts/apps/rhythmbox/script.py
index 933d627..a965800 100644
--- a/src/orca/scripts/apps/rhythmbox/script.py
+++ b/src/orca/scripts/apps/rhythmbox/script.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,13 +22,14 @@
 __id__ = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import orca.default as default
 
 from speech_generator import SpeechGenerator
 from braille_generator import BrailleGenerator
+from formatting import Formatting
 
 class Script(default.Script):
 
@@ -43,10 +44,13 @@ class Script(default.Script):
     def getBrailleGenerator(self):
         """Returns the braille generator for this script.
         """
-
         return BrailleGenerator(self)
 
     def getSpeechGenerator(self):
         """Returns the speech generator for this script.
         """
         return SpeechGenerator(self)
+
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
diff --git a/src/orca/scripts/apps/rhythmbox/speech_generator.py b/src/orca/scripts/apps/rhythmbox/speech_generator.py
index 8b5eba9..5279aa6 100644
--- a/src/orca/scripts/apps/rhythmbox/speech_generator.py
+++ b/src/orca/scripts/apps/rhythmbox/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,72 +22,27 @@
 __id__ = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
-import pyatspi
-import orca.speechgenerator as speechgenerator
+import orca.speech_generator as speech_generator
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
-    """Overrides _getSpeechForTableCell to correctly handle the table
+class SpeechGenerator(speech_generator.SpeechGenerator):
+
+    # pylint: disable-msg=W0142
+
+    """Overrides _getRealTableCell to correctly handle the table
     cells in the Library table.
     """
-
     def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def _getSpeechForTableCell(self, obj, already_focused):
-        """Get the speech utterances for a single table cell
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
+        speech_generator.SpeechGenerator.__init__(self, script)
 
+    def _getRealTableCell(self, obj, **args):
         # Check to see if this is a table cell from the Library table.
         # If so, it'll have five children and we are interested in the
         # penultimate one. See bug #512639 for more details.
         #
         if obj.childCount == 5:
             obj = obj[3]
-        return speechgenerator.SpeechGenerator.\
-                    _getSpeechForTableCell(self, obj, already_focused)
-
-    def _getDefaultSpeech(self, obj, already_focused, role=None):
-        """Gets a list of utterances to be spoken for the current
-        object's name, role, and any accelerators.  This is usually the
-        fallback speech generator should no other specialized speech
-        generator exist for this object.
-
-        The default speech will be of the following form:
-
-        label name role availability
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-        - role: A role that should be used instead of the Accessible's 
-          possible role.
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # When the rating widget changes values, it emits an accessible
-        # name changed event. Because it is of ROLE_UNKNOWN, the default
-        # speechgenerator's _getDefaultSpeech handles it. And because
-        # the widget is already focused, it doesn't speak anything. We
-        # want to speak the widget's name as it contains the number of
-        # stars being displayed.
-        #
-        if obj.getRole() == pyatspi.ROLE_UNKNOWN and already_focused:
-            utterances = self._getSpeechForObjectName(obj)
-            self._debugGenerator("rhythmbox _getDefaultSpeech",
-                                 obj,
-                                 already_focused,
-                                 utterances)
-            return utterances
-
-        return speechgenerator.SpeechGenerator.\
-                        _getDefaultSpeech(self, obj, already_focused, role)
+        return speech_generator.SpeechGenerator._getRealTableCell(
+            self, obj, **args)
diff --git a/src/orca/scripts/apps/soffice/Makefile.am b/src/orca/scripts/apps/soffice/Makefile.am
index 04741ad..5d9c71b 100644
--- a/src/orca/scripts/apps/soffice/Makefile.am
+++ b/src/orca/scripts/apps/soffice/Makefile.am
@@ -1,8 +1,9 @@
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
-	braille_generator.py \
 	__init__.py \
+	braille_generator.py \
+	formatting.py \
 	script.py \
 	script_settings.py \
 	speech_generator.py \
diff --git a/src/orca/scripts/apps/soffice/formatting.py b/src/orca/scripts/apps/soffice/formatting.py
new file mode 100644
index 0000000..57dc619
--- /dev/null
+++ b/src/orca/scripts/apps/soffice/formatting.py
@@ -0,0 +1,62 @@
+# Orca
+#
+# Copyright 2005-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for OpenOffice and StarOffice."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+# pylint: disable-msg=C0301
+
+import copy
+
+import pyatspi
+
+import orca.formatting
+
+formatting = {
+    'speech': {
+        # Get rid of unselectedCell because we don't run into that in OOo
+        # and we'd end up always speaking "not selected" for all table cells.
+        #
+        'suffix': {
+            'focused': '[]',
+            'unfocused': 'newNodeLevel + tutorial'
+            },
+        pyatspi.ROLE_COMBO_BOX: {
+            'focused': 'name + availability',
+            'unfocused': 'labelAndName + roleName + availability'
+            },
+        pyatspi.ROLE_PUSH_BUTTON: {
+            'unfocused': 'labelAndName + roleName + toggleState + availability',
+            'focused': 'labelAndName + toggleState'
+            },
+        pyatspi.ROLE_TOGGLE_BUTTON: {
+            'focused': 'labelAndName + toggleState'
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
diff --git a/src/orca/scripts/apps/soffice/script.py b/src/orca/scripts/apps/soffice/script.py
index e4dc82e..99688e2 100644
--- a/src/orca/scripts/apps/soffice/script.py
+++ b/src/orca/scripts/apps/soffice/script.py
@@ -55,6 +55,7 @@ from orca.structural_navigation import StructuralNavigation
 
 from speech_generator import SpeechGenerator
 from braille_generator import BrailleGenerator
+from formatting import Formatting
 from where_am_i import WhereAmI
 import script_settings
 
@@ -185,15 +186,17 @@ class Script(default.Script):
     def getBrailleGenerator(self):
         """Returns the braille generator for this script.
         """
-
         return BrailleGenerator(self)
 
     def getSpeechGenerator(self):
         """Returns the speech generator for this script.
         """
-
         return SpeechGenerator(self)
 
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
+
     def getEnabledStructuralNavigationTypes(self):
         """Returns a list of the structural navigation object types
         enabled in this script.
@@ -206,7 +209,6 @@ class Script(default.Script):
     def getWhereAmI(self):
         """Returns the "where am I" class for this script.
         """
-
         return WhereAmI(self)
 
     def setupInputEventHandlers(self):
@@ -438,12 +440,13 @@ class Script(default.Script):
         isn't in a table.
         """
 
+        table = None
         obj = self.adjustForWriterTable(obj)
         if obj.getRole() == pyatspi.ROLE_TABLE_CELL and obj.parent:
             try:
                 table = obj.parent.queryTable()
             except NotImplementedError:
-                table = None
+                pass
 
         return table
 
@@ -778,14 +781,17 @@ class Script(default.Script):
             return (cell != None)
 
         self.updateBraille(cell)
-        utterances = self.speechGenerator.getSpeech(cell, False)
+        utterances = self.speechGenerator.getSpeech(cell)
+        # [[[TODO: WDW - need to make sure assumption about utterances[0]
+        # is still correct with the new speech generator stuff.]]]
+        #
         if not len(utterances[0]) and self.speakBlankLine(newFocus):
             # Translators: "blank" is a short word to mean the
             # user has navigated to an empty line.
             #
             speech.speak(_("blank"), None, False)
         else:
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
         if not settings.readTableCellRow:
             self.speakCellName(cell.name)
@@ -1533,9 +1539,8 @@ class Script(default.Script):
         if self.isSpreadSheetCell(event.source, True):
             if newLocusOfFocus:
                 self.updateBraille(newLocusOfFocus)
-                utterances = self.speechGenerator.getSpeech(newLocusOfFocus,
-                                                            False)
-                speech.speakUtterances(utterances)
+                utterances = self.speechGenerator.getSpeech(newLocusOfFocus)
+                speech.speak(utterances)
 
                 # Save the current row and column information in the table
                 # cell's table, so that we can use it the next time.
@@ -1571,9 +1576,8 @@ class Script(default.Script):
                     for tab in child:
                         eventState = tab.getState()
                         if eventState.contains(pyatspi.STATE_SELECTED):
-                            utterances = self.speechGenerator.getSpeech(tab,
-                                                                        False)
-                            speech.speakUtterances(utterances)
+                            utterances = self.speechGenerator.getSpeech(tab)
+                            speech.speak(utterances)
             # Fall-thru to process the event with the default handler.
 
         # If we are focused on a place holder element in the slide
@@ -1871,8 +1875,7 @@ class Script(default.Script):
                 weToggledIt = wasCommand and keyString not in navKeys
 
             if weToggledIt:
-                speech.speakUtterances(self.speechGenerator.getSpeech( \
-                                       event.source, False))
+                speech.speak(self.speechGenerator.getSpeech(event.source))
 
         # When a new paragraph receives focus, we get a caret-moved event and
         # two focus events (the first being object:state-changed:focused).
diff --git a/src/orca/scripts/apps/soffice/speech_generator.py b/src/orca/scripts/apps/soffice/speech_generator.py
index 45d9a71..7a3ae41 100644
--- a/src/orca/scripts/apps/soffice/speech_generator.py
+++ b/src/orca/scripts/apps/soffice/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,230 +22,214 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
 
-import orca.speechgenerator as speechgenerator
+import orca.speech_generator as speech_generator
 import orca.settings as settings
 
 from orca.orca_i18n import _ # for gettext support
 
 import script_settings
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
-    """Overrides _getSpeechForComboBox so that we can provide a name for
-    the Calc Name combo box.
-    Overrides _getSpeechForTableCellRow so that , when we are in a
-    spread sheet, we can speak the dynamic row and column headers
-    (assuming they are set).
-    Overrides _getSpeechForTableCell so that, when we are in a spread
-    sheet, we can speak the location of the table cell as well as the
-    contents.
-    Overrides _getSpeechForToggleButton so that, when the toggle buttons
-    on the Formatting toolbar change state, we provide both the name and
-    the state (as "on" or "off")
-    Overrides _getSpeechForPushButton because sometimes the toggle buttons
-    on the Formatting toolbar claim to be push buttons.
-    """
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def getSpeechForObjectRole(self, obj, role=None):
-        if obj.getRoleName() == "text frame" \
-           or (obj.getRole() == pyatspi.ROLE_PARAGRAPH \
-               and self._script.getAncestor(obj,
-                                            [pyatspi.ROLE_DIALOG],
-                                            [pyatspi.ROLE_APPLICATION])):
-            role = pyatspi.ROLE_TEXT
-            
-        return speechgenerator.SpeechGenerator.\
-            getSpeechForObjectRole(self, obj, role)
-
-    def _getSpeechForComboBox(self, obj, already_focused):
-        """Get the speech for a combo box. If the combo box already has focus,
-        then only the selection is spoken.
-        Also provides a name for the OOo Calc Name combo box. This name is
-        provided in clause 5) of locusOfFocusChanged() below.
-
-        Arguments:
-        - obj: the combo box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            if not label:
-                label = [ obj.name ]
-            utterances.extend(label)
-        else:
-            label = None
-
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-
-        if not already_focused:
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("_getSpeechForComboBox",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
+class SpeechGenerator(speech_generator.SpeechGenerator):
 
-    def _getSpeechForTable(self, obj, already_focused):
-        """Get the speech for a table
+    # pylint: disable-msg=W0142
 
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTable",
-                             obj,
-                             already_focused,
-                             utterances)
+    def __init__(self, script):
+        speech_generator.SpeechGenerator.__init__(self, script)
 
-        # If this is a table with no children, then let the user know.
+    def __overrideParagraph(self, obj, **args):
+        # Treat a paragraph which is serving as a text entry in a dialog
+        # as a text object.
         #
-        if not obj.childCount:
-            # Translators: this indicates that there are zero items in
-            # a layered pane or table.
+        role = args.get('role', obj.getRole())
+        override = \
+            role == "text frame" \
+            or (role == pyatspi.ROLE_PARAGRAPH \
+                and self._script.getAncestor(obj,
+                                             [pyatspi.ROLE_DIALOG],
+                                             [pyatspi.ROLE_APPLICATION]))
+        return override
+
+    def _getRoleName(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        if role in [pyatspi.ROLE_PUSH_BUTTON, pyatspi.ROLE_TOGGLE_BUTTON] \
+           and obj.parent.getRole() == pyatspi.ROLE_TOOL_BAR:
+            # We don't speak roles for the objects in the toolbar.
             #
-            utterances.append(_("0 items"))
-
-        return utterances
-
-    def _getSpeechForTableCellRow(self, obj, already_focused):
-        """Get the speech for a table cell row or a single table cell
-        if settings.readTableCellRow is False. If this isn't inside a
-        spread sheet, just return the utterances returned by the default
-        table cell speech handler.
-
-        Arguments:
-        - obj: the table cell
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-
-            # Check to see if this spread sheet cell has either a dynamic
-            # column heading or row heading (or both) associated with it.
-            # If it does, then speak those first before speaking the cell
-            # contents.
+            pass
+        else:
+            # Treat a paragraph which is serving as a text entry in a dialog
+            # as a text object.
             #
-            table = self._script.getTable(obj)
-            parent = obj.parent
-            try:
-                parentTable = parent.queryTable()
-            except NotImplementedError:
-                parentTable = None
-
-            index = self._script.getCellIndex(obj)
-            if "lastColumn" in self._script.pointOfReference and \
-               self._script.pointOfReference["lastColumn"] != \
-               parentTable.getColumnAtIndex(index):
-                if table in self._script.dynamicColumnHeaders:
-                    row = self._script.dynamicColumnHeaders[table]
-                    header = self._script.getDynamicRowHeaderCell(obj, row)
-                    try:
-                        headerText = header.queryText()
-                    except:
-                        headerText = None
-
-                    if header.childCount > 0:
-                        for child in header:
-                            text = self._script.getText(child, 0, -1)
-                            if text:
-                                utterances.append(text)
-                    elif headerText:
-                        text = self._script.getText(header, 0, -1)
+            override = self.__overrideParagraph(obj, **args)
+            if override:
+                oldRole = self._overrideRole(pyatspi.ROLE_TEXT, args)
+            result.extend(speech_generator.SpeechGenerator._getRoleName(
+                          self, obj, **args))
+            if override:
+                self._restoreRole(oldRole, args)
+        return result
+
+    def _getTextRole(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        if role != pyatspi.ROLE_PARAGRAPH \
+           or self.__overrideParagraph(obj, **args):
+            result.extend(self._getRoleName(obj, **args))
+        return result
+
+    def _getLabelOrName(self, obj, **args):
+        """Gets the label or the name if the label is not preset."""
+        result = []
+        override = self.__overrideParagraph(obj, **args)
+        # Treat a paragraph which is serving as a text entry in a dialog
+        # as a text object.
+        #
+        if override:
+            result.extend(self._getLabel(obj, **args))
+            if len(result) == 0 and obj.parent:
+                parentLabel = self._getLabel(obj.parent, **args)
+                # If we aren't already focused, we will have spoken the
+                # parent as part of the speech context and do not want
+                # to repeat it.
+                #
+                already_focused = args.get('already_focused', False)
+                if already_focused:
+                    result.extend(parentLabel)
+                # If we still don't have a label, look to the name.
+                #
+                if not parentLabel and obj.name and len(obj.name):
+                    result.append(obj.name)
+        else:
+            result.extend(speech_generator.SpeechGenerator._getLabelOrName(
+                self, obj, **args))
+        return result
+
+    def _getToggleState(self, obj, **args):
+        """Treat push buttons (which act like toggle buttons) and toggle
+        buttons in the toolbar specially.  This is so we can have more
+        natural sounding speech such as "bold on", "bold off", etc."""
+        result = []
+        role = args.get('role', obj.getRole())
+        if role in [pyatspi.ROLE_PUSH_BUTTON, pyatspi.ROLE_TOGGLE_BUTTON] \
+           and obj.parent.getRole() == pyatspi.ROLE_TOOL_BAR:
+            if obj.getState().contains(pyatspi.STATE_CHECKED):
+                # Translators: this represents the state of a check box
+                #
+                result.append(_("on"))
+            else:
+                # Translators: this represents the state of a check box
+                #
+                result.append(_("off"))
+        elif role == pyatspi.ROLE_TOGGLE_BUTTON:
+            result.extend(speech_generator.SpeechGenerator._getToggleState(
+                self, obj, **args))
+        return result
+
+    def _getNewRowHeader(self, obj, **args):
+        result = []
+        # Check to see if this spread sheet cell has either a dynamic
+        # row heading associated with it.
+        #
+        table = self._script.getTable(obj)
+        parent = obj.parent
+        try:
+            parentTable = parent.queryTable()
+        except NotImplementedError:
+            parentTable = None
+        index = self._script.getCellIndex(obj)
+        if "lastRow" in self._script.pointOfReference and \
+           self._script.pointOfReference["lastRow"] != \
+           parentTable.getRowAtIndex(index):
+            if table in self._script.dynamicRowHeaders:
+                column = self._script.dynamicRowHeaders[table]
+                header = self._script.getDynamicColumnHeaderCell(obj, column)
+                try:
+                    headerText = header.queryText()
+                except:
+                    headerText = None
+                if header.childCount > 0:
+                    for child in header:
+                        text = self._script.getText(child, 0, -1)
                         if text:
-                            utterances.append(text)
-
-            if "lastRow" in self._script.pointOfReference and \
-               self._script.pointOfReference["lastRow"] != \
-               parentTable.getRowAtIndex(index):
-                if table in self._script.dynamicRowHeaders:
-                    column = self._script.dynamicRowHeaders[table]
-                    header = self._script.getDynamicColumnHeaderCell(obj,
-                                                                     column)
-                    try:
-                        headerText = header.queryText()
-                    except:
-                        headerText = None
-
-                    if header.childCount > 0:
-                        for child in header:
-                            text = self._script.getText(child, 0, -1)
-                            if text:
-                                utterances.append(text)
-                    elif headerText:
-                        text = self._script.getText(header, 0, -1)
+                            result.append(text)
+                elif headerText:
+                    text = self._script.getText(header, 0, -1)
+                    if text:
+                        result.append(text)
+        return result
+
+    def _getNewColumnHeader(self, obj, **args):
+        result = []
+        # Check to see if this spread sheet cell has either a dynamic
+        # row heading associated with it.
+        #
+        table = self._script.getTable(obj)
+        parent = obj.parent
+        try:
+            parentTable = parent.queryTable()
+        except NotImplementedError:
+            parentTable = None
+        index = self._script.getCellIndex(obj)
+        if "lastColumn" in self._script.pointOfReference and \
+           self._script.pointOfReference["lastColumn"] != \
+           parentTable.getColumnAtIndex(index):
+            if table in self._script.dynamicColumnHeaders:
+                row = self._script.dynamicColumnHeaders[table]
+                header = self._script.getDynamicRowHeaderCell(obj, row)
+                try:
+                    headerText = header.queryText()
+                except:
+                    headerText = None
+                if header.childCount > 0:
+                    for child in header:
+                        text = self._script.getText(child, 0, -1)
                         if text:
-                            utterances.append(text)
-
-        if self._script.isSpreadSheetCell(obj):
-            if not already_focused:
-                if settings.readTableCellRow:
-                    parent = obj.parent
-                    index = self._script.getCellIndex(obj)
-                    row = parentTable.getRowAtIndex(index)
-                    column = parentTable.getColumnAtIndex(index)
-
-                    # This is an indication of whether we should speak all the
-                    # table cells (the user has moved focus up or down a row),
-                    # or just the current one (focus has moved left or right in
-                    # the same row).
+                            result.append(text)
+                elif headerText:
+                    text = self._script.getText(header, 0, -1)
+                    if text:
+                        result.append(text)
+        return result
+
+    def _getSpreadSheetCell(self, obj, **args):
+        result = []
+        if self._script.inputLineForCell == None:
+            self._script.inputLineForCell = \
+                self._script.locateInputLine(obj)
+        try:
+            if obj.queryText():
+                objectText = self._script.getText(obj, 0, -1)
+                if not script_settings.speakCellCoordinates \
+                   and len(objectText) == 0:
+                    # Translators: this indicates an empty (blank) spread
+                    # sheet cell.
                     #
-                    speakAll = True
-                    if "lastRow" in self._script.pointOfReference and \
-                        "lastColumn" in self._script.pointOfReference:
-                        pointOfReference = self._script.pointOfReference
-                        speakAll = (pointOfReference["lastRow"] != row) or \
-                               ((row == 0 or row == parentTable.nRows-1) and \
-                                pointOfReference["lastColumn"] == column)
-
-                    if speakAll:
-                        [startIndex, endIndex] = \
-                            self._script.getSpreadSheetRowRange(obj)
-                        for i in range(startIndex, endIndex+1):
-                            cell = parentTable.getAccessibleAt(row, i)
-                            showing = cell.getState().contains( \
-                                          pyatspi.STATE_SHOWING)
-                            if showing:
-                                utterances.extend(self._getSpeechForTableCell(\
-                                                  cell, already_focused))
-                    else:
-                        utterances.extend(self._getSpeechForTableCell(obj,
-                                                             already_focused))
-                else:
-                    utterances.extend(self._getSpeechForTableCell(obj,
-                                                             already_focused))
-        else:
-            utterances.extend(speechgenerator.SpeechGenerator.\
-                _getSpeechForTableCellRow(self, obj, already_focused))
-
-        return utterances
+                    objectText = _("blank")
+                result.append(objectText)
+        except NotImplementedError:
+            pass
+
+        if script_settings.speakCellCoordinates:
+            nameList = obj.name.split()
+            # We were assuming that the word for "cell" would always
+            # precede the coordinates. This is not the case for all
+            # languages (e.g. Hungarian). See bug #562532. Therefore
+            # examine each item and choose the one which contains a
+            # digit.
+            #
+            for name in nameList:                    
+                for char in name.decode("UTF-8"):
+                    if char.isdigit():
+                        result.append(name)
+        return result
 
-    def _getSpeechForTableCell(self, obj, already_focused):
+    def _getRealTableCell(self, obj, **args):
         """Get the speech for a table cell. If this isn't inside a
         spread sheet, just return the utterances returned by the default
         table cell speech handler.
@@ -256,41 +240,9 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
 
         Returns a list of utterances to be spoken for the object.
         """
-
+        result = []
         if self._script.isSpreadSheetCell(obj):
-            utterances = []
-
-            if self._script.inputLineForCell == None:
-                self._script.inputLineForCell = \
-                            self._script.locateInputLine(obj)
-
-            try:
-                if obj.queryText():
-                    objectText = self._script.getText(obj, 0, -1)
-                    if not script_settings.speakCellCoordinates and \
-                            len(objectText) == 0:
-                        # Translators: this indicates an empty (blank) spread
-                        # sheet cell.
-                        #
-                        objectText = _("blank")
-
-                    utterances.append(objectText)
-            except NotImplementedError:
-                pass
-
-            if script_settings.speakCellCoordinates:
-                nameList = obj.name.split()
-                # We were assuming that the word for "cell" would always
-                # precede the coordinates. This is not the case for all
-                # languages (e.g. Hungarian). See bug #562532. Therefore
-                # examine each item and choose the one which contains a
-                # digit.
-                #
-                for name in nameList:                    
-                    for char in name.decode("UTF-8"):
-                        if char.isdigit():
-                            utterances.append(name)
-                            return utterances
+            result.extend(self._getSpreadSheetCell(obj, **args))
         else:
             # Check to see how many children this table cell has. If it's
             # just one (or none), then pass it on to the superclass to be
@@ -300,115 +252,59 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
             # and call this method again.
             #
             if obj.childCount <= 1:
-                utterances = speechgenerator.SpeechGenerator.\
-                    _getSpeechForTableCell(self, obj, already_focused)
+                result.extend(speech_generator.SpeechGenerator.\
+                              _getRealTableCell(self, obj, **args))
             else:
-                utterances = []
                 for child in obj:
-                    utterances.extend(self._getSpeechForTableCell(child,
-                                                        already_focused))
-
-        return utterances
-
-    def _getSpeechForText(self, obj, already_focused):
-        """Get the speech for a paragraph which is serving as a text object
-        in a dialog.
-
-        Arguments:
-        - obj: the text component
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-        if obj.getRole() == pyatspi.ROLE_PARAGRAPH \
-           and self._script.getAncestor(obj,
-                                        [pyatspi.ROLE_DIALOG],
-                                        [pyatspi.ROLE_APPLICATION]):
-            utterances.extend(self._getSpeechForObjectLabel(obj))
-            if len(utterances) == 0 and obj.parent:
-                parentLabel = self._getSpeechForObjectLabel(obj.parent)
-                # If we aren't already focused, we will have spoken the
-                # parent as part of the speech context and do not want
-                # to repeat it.
-                #
-                if already_focused:
-                    utterances.extend(parentLabel)
-                # If we still don't have a label, look to the name.
-                #
-                if not parentLabel and obj.name and len(obj.name):
-                    utterances.append(obj.name)
-
-            utterances.append(self._script.getTextLineAtCaret(obj)[0])
-            utterances.extend(self._getSpeechForAllTextSelection(obj))
-
-            self._debugGenerator("soffice _getSpeechForText",
-                                 obj,
-                                 already_focused,
-                                 utterances)
-        else:
-            utterances.extend(speechgenerator.SpeechGenerator.\
-                _getSpeechForText(self, obj, already_focused))
+                    result.extend(self._getRealTableCell(child, **args))
+        return result
 
-        return utterances
-
-    def _getSpeechForToggleButton(self, obj, already_focused):
-        """Get the speech for a toggle button.  We always want to speak the
-        state if it's on a toolbar.
-
-        Arguments:
-        - obj: the toggle button
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-        if obj.parent.getRole() == pyatspi.ROLE_TOOL_BAR:
-            if obj.getState().contains(pyatspi.STATE_CHECKED):
-                # Translators: this represents the state of a check box
-                #
-                checkedState = _("on")
-            else:
-                # Translators: this represents the state of a check box
-                #
-                checkedState = _("off")
-
-            utterances.append(obj.name)
-            utterances.append(checkedState)
-        else:
-            utterances.extend(speechgenerator.SpeechGenerator.\
-                _getSpeechForToggleButton(self, obj, already_focused))
-
-        return utterances
-
-    def _getSpeechForPushButton(self, obj, already_focused):
-        """Get the speech for a push button.  We always want to speak the
-        state if it's on a toolbar.
+    def _getTableCellRow(self, obj, **args):
+        """Get the speech for a table cell row or a single table cell
+        if settings.readTableCellRow is False. If this isn't inside a
+        spread sheet, just return the utterances returned by the default
+        table cell speech handler.
 
         Arguments:
-        - obj: the push button
+        - obj: the table cell
         - already_focused: False if object just received focus
 
         Returns a list of utterances to be spoken for the object.
         """
-
-        utterances = []
-        if obj.parent.getRole() == pyatspi.ROLE_TOOL_BAR:
-            if obj.getState().contains(pyatspi.STATE_CHECKED):
-                # Translators: this represents the state of a check box
+        result = []
+        if self._script.isSpreadSheetCell(obj):
+            if settings.readTableCellRow:
+                parent = obj.parent
+                parentTable = parent.queryTable()
+                index = self._script.getCellIndex(obj)
+                row = parentTable.getRowAtIndex(index)
+                column = parentTable.getColumnAtIndex(index)
+                # This is an indication of whether we should speak all the
+                # table cells (the user has moved focus up or down a row),
+                # or just the current one (focus has moved left or right in
+                # the same row).
                 #
-                checkedState = _("on")
+                speakAll = True
+                if "lastRow" in self._script.pointOfReference and \
+                    "lastColumn" in self._script.pointOfReference:
+                    pointOfReference = self._script.pointOfReference
+                    speakAll = (pointOfReference["lastRow"] != row) or \
+                           ((row == 0 or row == parentTable.nRows-1) and \
+                            pointOfReference["lastColumn"] == column)
+                if speakAll:
+                    [startIndex, endIndex] = \
+                        self._script.getSpreadSheetRowRange(obj)
+                    for i in range(startIndex, endIndex+1):
+                        cell = parentTable.getAccessibleAt(row, i)
+                        showing = cell.getState().contains( \
+                                      pyatspi.STATE_SHOWING)
+                        if showing:
+                            result.extend(self._getRealTableCell(cell, **args))
+                else:
+                    result.extend(self._getRealTableCell(obj, **args))
             else:
-                # Translators: this represents the state of a check box
-                #
-                checkedState = _("off")
-
-            utterances.append(obj.name)
-            utterances.append(checkedState)
+                result.extend(self._getRealTableCell(obj, **args))
         else:
-            utterances.extend(speechgenerator.SpeechGenerator.\
-                _getSpeechForPushButton(self, obj, already_focused))
-
-        return utterances
+            result.extend(speech_generator.SpeechGenerator._getTableCellRow(
+                          self, obj, **args))
+        return result
diff --git a/src/orca/scripts/apps/soffice/where_am_i.py b/src/orca/scripts/apps/soffice/where_am_i.py
index 8b557f3..c1b909e 100644
--- a/src/orca/scripts/apps/soffice/where_am_i.py
+++ b/src/orca/scripts/apps/soffice/where_am_i.py
@@ -124,7 +124,7 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel, "calc table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakParagraph(self, obj, basicOnly):
         """OpenOffice Calc cells have the role "paragraph" when
@@ -161,7 +161,7 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel, "editable table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _getCalcFrameAndSheet(self, obj):
         """Returns the Calc frame and sheet
@@ -196,7 +196,7 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel, "Calc statusbar utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def speakTitle(self, obj):
         """Speak the title bar.
@@ -226,7 +226,7 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel,
                       "Calc titlebar and sheet utterances=%s" % utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def speakStatusBar(self, obj):
         """Speak the status bar contents.
@@ -250,7 +250,7 @@ class WhereAmI(where_am_I.WhereAmI):
 
         debug.println(self._debugLevel,
                       "Calc status bar utterances=%s" % utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _getObjLabel(self, obj):
         """Returns the label to speak for an object.
diff --git a/src/orca/scripts/apps/yelp.py b/src/orca/scripts/apps/yelp.py
index 5964582..0b3979a 100644
--- a/src/orca/scripts/apps/yelp.py
+++ b/src/orca/scripts/apps/yelp.py
@@ -202,8 +202,7 @@ class Script(Gecko.Script):
                 self._currentFrameName = event.source.name
                 self.setCaretPosition(obj, characterOffset)
                 if obj.getState().contains(pyatspi.STATE_FOCUSED):
-                    speech.speakUtterances(\
-                        self.speechGenerator.getSpeech(obj, False))
+                    speech.speak(self.speechGenerator.getSpeech(obj))
                 elif not Gecko.script_settings.sayAllOnLoad:
                     self.speakContents(\
                         self.getLineContentsAtOffset(obj, characterOffset))
diff --git a/src/orca/scripts/toolkits/Gecko/Makefile.am b/src/orca/scripts/toolkits/Gecko/Makefile.am
index af9a261..2de2e09 100644
--- a/src/orca/scripts/toolkits/Gecko/Makefile.am
+++ b/src/orca/scripts/toolkits/Gecko/Makefile.am
@@ -1,9 +1,10 @@
 orca_pathdir=$(pyexecdir)
 
 orca_python_PYTHON = \
+	__init__.py \
 	bookmarks.py \
 	braille_generator.py \
-	__init__.py \
+	formatting.py \
 	script.py \
 	script_settings.py \
 	speech_generator.py \
diff --git a/src/orca/scripts/toolkits/Gecko/bookmarks.py b/src/orca/scripts/toolkits/Gecko/bookmarks.py
index faab4f8..5f97392 100644
--- a/src/orca/scripts/toolkits/Gecko/bookmarks.py
+++ b/src/orca/scripts/toolkits/Gecko/bookmarks.py
@@ -62,7 +62,7 @@ class GeckoBookmarks(bookmarks.Bookmarks):
         utterances = [(_('entered bookmark'))]
         utterances.extend(self._script.speechGenerator.getSpeech \
                          (obj, False))
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
         
     def goToBookmark(self, inputEvent, index=None):
         """ Go to the bookmark indexed at this key and this page's URI """
diff --git a/src/orca/scripts/toolkits/Gecko/formatting.py b/src/orca/scripts/toolkits/Gecko/formatting.py
new file mode 100644
index 0000000..7f8492a
--- /dev/null
+++ b/src/orca/scripts/toolkits/Gecko/formatting.py
@@ -0,0 +1,84 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for Gecko."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import copy
+
+import pyatspi
+
+import orca.formatting
+
+# pylint: disable-msg=C0301
+
+formatting = {
+    'speech': {
+        pyatspi.ROLE_ALERT: {
+            'unfocused': 'expandedEOCs or (labelAndName + unrelatedLabels)'
+            },
+        pyatspi.ROLE_DIALOG: {
+            'unfocused': 'expandedEOCs or (labelAndName + unrelatedLabels)'
+            },
+        pyatspi.ROLE_DOCUMENT_FRAME: {
+            'unfocused': 'name + roleName'
+            },
+        pyatspi.ROLE_LINK: {
+            'unfocused': 'labelAndName + roleName + availability'
+            },
+        pyatspi.ROLE_LIST: {
+            'focused': 'focusedItem',
+            'unfocused': 'labelOrName + focusedItem + multiselectableState + numberOfChildren'
+            },
+        # [[[TODO: JD - We should decide if we want to provide
+        # information about the table dimensions, whether or not
+        # this is a layout table versus a data table, etc.  For now,
+        # however, if it's in HTML content let's ignore it so that
+        # SayAll by sentence works. :-) ]]]
+        #
+        pyatspi.ROLE_TABLE: {
+            'unfocused': '[]'
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+
+    # pylint: disable-msg=W0142
+
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
+        # This is a copy of the default formatting, which we will
+        # use for ARIA widgets.
+        #
+        self._defaultFormatting = orca.formatting.Formatting(script)
+
+    def getFormat(self, dictType, **args):
+        # ARIA widgets get treated like regular default widgets.
+        #
+        if args.get('isAria', False):
+            return self._defaultFormatting.getFormat(dictType, **args)
+        else:
+            return orca.formatting.Formatting.getFormat(self, dictType, **args)
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index 4ef5a5a..dab5aef 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -64,13 +64,13 @@ import orca.speechserver as speechserver
 import script_settings
 from braille_generator import BrailleGenerator
 from speech_generator import SpeechGenerator
+from formatting import Formatting
 from where_am_i import GeckoWhereAmI
 from bookmarks import GeckoBookmarks
 from structural_navigation import GeckoStructuralNavigation
 
 from orca.orca_i18n import _
 
-
 ########################################################################
 #                                                                      #
 # Script                                                               #
@@ -310,6 +310,10 @@ class Script(default.Script):
         """
         return SpeechGenerator(self)
 
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
+
     def getEnabledStructuralNavigationTypes(self):
         """Returns a list of the structural navigation object types
         enabled in this script.
@@ -1551,9 +1555,9 @@ class Script(default.Script):
             utterances.append(rolenames.getSpeechForRoleName(event.any_data))
             if settings.speechVerbosityLevel == \
                     settings.VERBOSITY_LEVEL_VERBOSE:
-                utterances.extend(\
-                    self.speechGenerator.getSpeech(event.any_data, False))
-            speech.speakUtterances(utterances)
+                utterances.extend(
+                    self.speechGenerator.getSpeech(event.any_data))
+            speech.speak(utterances)
 
     def onDocumentReload(self, event):
         """Called when the reload button is hit for a web page."""
@@ -1684,8 +1688,8 @@ class Script(default.Script):
                     # http://bugzilla.gnome.org/show_bug.cgi?id=570551
                     #
                     if eventSourceRole == pyatspi.ROLE_ALERT:
-                        speech.speakUtterances(\
-                            self.speechGenerator.getSpeech(event.source, False))
+                        speech.speak(self.speechGenerator.getSpeech(
+                                event.source))
                         self.updateBraille(obj)
                     else:
                         self.presentLine(obj, characterOffset)
@@ -1874,8 +1878,7 @@ class Script(default.Script):
                     self.updateBraille(obj)
 
                     if obj.getState().contains(pyatspi.STATE_FOCUSABLE):
-                        speech.speakUtterances(\
-                            self.speechGenerator.getSpeech(obj, False))
+                        speech.speak(self.speechGenerator.getSpeech(obj))
                     elif not script_settings.sayAllOnLoad:
                         self.speakContents(\
                             self.getLineContentsAtOffset(obj,
@@ -2437,7 +2440,7 @@ class Script(default.Script):
 
         # Ideally in an entry we would just let default.sayWord() handle
         # things.  That fails to work when navigating backwords by word.
-        # Because getUtterancesFromContents() now uses the speechgenerator
+        # Because getUtterancesFromContents() now uses the speech_generator
         # with entries, we need to handle word navigation in entries here.
         #
         wordContents = self.getWordContentsAtOffset(obj, characterOffset)
@@ -2446,7 +2449,7 @@ class Script(default.Script):
         else:
             [textObj, startOffset, endOffset, word] = wordContents[0]
             word = textObj.queryText().getText(startOffset, endOffset)
-            speech.speakUtterances([word], self.getACSS(textObj, word))
+            speech.speak([word], self.getACSS(textObj, word))
 
     def sayLine(self, obj):
         """Speaks the line at the current caret position."""
@@ -3604,7 +3607,7 @@ class Script(default.Script):
         this value is 0-based (Gecko return is 1-based) """
 
         if obj is None or obj.getRole() == pyatspi.ROLE_HEADING \
-           or obj.parent.getRole() == pyatspi.ROLE_MENU:
+           or (obj.parent and obj.parent.getRole() == pyatspi.ROLE_MENU):
             return -1
 
         try:
@@ -3617,6 +3620,8 @@ class Script(default.Script):
                 # seems to be guilty of this.
                 #
                 #print "getNodeLevel - obj is defunct", obj
+                debug.println(debug.LEVEL_WARNING,
+                              "getNodeLevel - obj is defunct")
                 debug.printStack(debug.LEVEL_WARNING)
                 return -1
 
@@ -5337,11 +5342,14 @@ class Script(default.Script):
     #                                                                  #
     ####################################################################
 
+    # [[[TODO: WDW - this needs to be moved to the speech generator.]]]
+    #
     def getACSS(self, obj, string):
         """Returns the ACSS to speak anything for the given obj."""
         if obj.getRole() == pyatspi.ROLE_LINK:
             acss = self.voices[settings.HYPERLINK_VOICE]
-        elif string and string.isupper() and string.strip().isalpha():
+        elif string and string.isupper() \
+             and string.strip().isalpha() and len(string.strip()) > 1:
             acss = self.voices[settings.UPPERCASE_VOICE]
         else:
             acss = self.voices[settings.DEFAULT_VOICE]
@@ -5423,12 +5431,12 @@ class Script(default.Script):
             #
             if not len(string) \
                or role in [pyatspi.ROLE_ENTRY, pyatspi.ROLE_PASSWORD_TEXT]:
-                utterance = self.speechGenerator.getSpeech(obj, False)
+                utterance = self.speechGenerator.getSpeech(obj)
             else:
                 utterance = [string]
                 if speakRole and not role in doNotSpeakRoles:
                     utterance.extend(\
-                        self.speechGenerator.getSpeechForObjectRole(obj))
+                        self.speechGenerator.getRoleName(obj))
   
             # If the object is a heading, or is contained within a heading,
             # speak that role information at the end of the object.
@@ -5445,7 +5453,7 @@ class Script(default.Script):
 
                 if heading:
                     utterance.extend(\
-                        self.speechGenerator.getSpeechForObjectRole(heading))
+                        self.speechGenerator.getRoleName(heading))
 
             for item in utterance:
                 utterances.append([item, self.getACSS(obj, item)])
@@ -5509,8 +5517,8 @@ class Script(default.Script):
                 # characterOffset (lists).  In these latter cases, we'll just
                 # speak the entire component.
                 #
-                utterances = self.speechGenerator.getSpeech(obj, False)
-                speech.speakUtterances(utterances)
+                utterances = self.speechGenerator.getSpeech(obj)
+                speech.speak(utterances)
 
     ####################################################################
     #                                                                  #
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index c3c8bd9..3f08fd1 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -26,18 +26,16 @@ http://developer.mozilla.org/en/docs/Accessibility/ATSPI_Support
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
 
 import orca.rolenames as rolenames
-import orca.settings as settings
-import orca.speechgenerator as speechgenerator
+import orca.speech_generator as speech_generator
 
 from orca.orca_i18n import _
 from orca.orca_i18n import ngettext # for ngettext support
-from orca.orca_i18n import C_       # to provide qualified translatable strings
 
 ########################################################################
 #                                                                      #
@@ -45,256 +43,136 @@ from orca.orca_i18n import C_       # to provide qualified translatable strings
 #                                                                      #
 ########################################################################
 
-class SpeechGenerator(speechgenerator.SpeechGenerator):
+class SpeechGenerator(speech_generator.SpeechGenerator):
     """Provides a speech generator specific to Gecko.
     """
 
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-        self.speechGenerators[pyatspi.ROLE_DOCUMENT_FRAME] = \
-             self._getSpeechForDocumentFrame
-        self.speechGenerators[pyatspi.ROLE_ENTRY]          = \
-             self._getSpeechForText
-        self.speechGenerators[pyatspi.ROLE_LINK]           = \
-             self._getSpeechForLink
-        self.speechGenerators[pyatspi.ROLE_LIST_ITEM]      = \
-             self._getSpeechForListItem
-        self.speechGenerators[pyatspi.ROLE_SLIDER]         = \
-             self._getSpeechForSlider
-
-    def getSpeechForObjectRole(self, obj, role=None):
-        """Prevents some roles from being spoken."""
-        doNotSpeak = [pyatspi.ROLE_FORM,
-                      pyatspi.ROLE_LABEL,
-                      pyatspi.ROLE_MENU_ITEM,
-                      pyatspi.ROLE_PARAGRAPH,
-                      pyatspi.ROLE_SECTION,
-                      pyatspi.ROLE_UNKNOWN]
-
-        if self._script.inDocumentContent(obj):
-            doNotSpeak.append(pyatspi.ROLE_TABLE_CELL)
-            if not self._script.isAriaWidget(obj):
-                doNotSpeak.append(pyatspi.ROLE_LIST_ITEM)
-                doNotSpeak.append(pyatspi.ROLE_LIST)
+    # pylint: disable-msg=W0142
 
-        utterances = []
-        if role or not obj.getRole() in doNotSpeak:
-            if obj.getRole() == pyatspi.ROLE_HEADING:
-                level = self._script.getHeadingLevel(obj)
-                if level:
-                    # Translators: the %(level)d is in reference to a heading
-                    # level in HTML (e.g., For <h3>, the level is 3)
-                    # and the %(role)s is in reference to a previously
-                    # translated rolename for the heading.
+    def __init__(self, script):
+        speech_generator.SpeechGenerator.__init__(self, script)
+
+    def _getName(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_COMBO_BOX:
+            # With Gecko, a combo box has a menu as a child.  The text being
+            # displayed for the combo box can be obtained via the selected
+            # menu item.
+            #
+            menu = None
+            for child in obj:
+                if child.getRole() == pyatspi.ROLE_MENU:
+                    menu = child
+                    break
+            if menu:
+                child = None
+                try:
+                    # This should work...
                     #
-                    utterances.append(_("%(role)s level %(level)d") % {
-                        'role': rolenames.getSpeechForRoleName(obj, role),
-                        'level': level})
-                else:
-                    utterances.append(rolenames.getSpeechForRoleName(obj, role))
-            else:
-                utterances.append(rolenames.getSpeechForRoleName(obj, role))
-
-        return utterances
-
-    def _getSpeechForAlert(self, obj, already_focused):
-        """Gets the speech for an alert.  What we do here is first try
-        to see if the alert contains text via embedded object characters.
-        If it does, we speak that text.  If it doesn't, we defer to the
-        super class.  The prototype alert we're shooting for is the one
-        from http://bugzilla.gnome.org/show_bug.cgi?id=570551
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        text = self._script.expandEOCs(obj)
-        if text:
-            return [text]
+                    child = menu.querySelection().getSelectedChild(0)
+                    if not child:
+                        # It's probably a Gtk combo box.
+                        #
+                        result = \
+                            speech_generator.SpeechGenerator._getDisplayedText(
+                                self, obj, **args)
+                except:
+                    # But just in case, we'll fall back on this.
+                    # [[[TODO - JD: Will we ever have a case where the first
+                    # fails, but this will succeed???]]]
+                    #
+                    for item in menu:
+                        if item.getState().contains(pyatspi.STATE_SELECTED):
+                            child = item
+                            break
+                if child and child.name:
+                    result.append(child.name)
         else:
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForAlert(self, obj, already_focused)
-
-    def _getSpeechForDocumentFrame(self, obj, already_focused):
-        """Gets the speech for a document frame.
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        name = obj.name
-        if name and len(name):
-            utterances.append(name)
-        utterances.extend(self.getSpeechForObjectRole(obj))
-
-        self._debugGenerator("Gecko._getSpeechForDocumentFrame",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForText(self, obj, already_focused):
-        """Gets the speech for an autocomplete box.
+            result.extend(speech_generator.SpeechGenerator._getName(self,
+                                                                    obj,
+                                                                    **args))
+        link = None
+        if role == pyatspi.ROLE_LINK:
+            link = obj
+        elif role == pyatspi.ROLE_IMAGE and not result:
+            link = self._script.getAncestor(obj,
+                                            [pyatspi.ROLE_LINK],
+                                            [pyatspi.ROLE_DOCUMENT_FRAME])
+        if link and (not result or len(result[0].strip()) == 0):
+            # If there's no text for the link, expose part of the
+            # URI to the user.
+            #
+            basename = self._script.getLinkBasename(link)
+            if basename:
+                result.append(basename)
 
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
+        return result
 
-        Returns a list of utterances to be spoken for the object.
-        """
+    def _getLabel(self, obj, **args):
+        result = speech_generator.SpeechGenerator._getLabel(self, obj, **args)
+        role = args.get('role', obj.getRole())
+        # We'll attempt to guess the label under some circumstances.
+        #
+        if not len(result) \
+           and role in [pyatspi.ROLE_CHECK_BOX,
+                        pyatspi.ROLE_COMBO_BOX,
+                        pyatspi.ROLE_ENTRY,
+                        pyatspi.ROLE_LIST,
+                        pyatspi.ROLE_PARAGRAPH,
+                        pyatspi.ROLE_PASSWORD_TEXT,
+                        pyatspi.ROLE_RADIO_BUTTON,
+                        pyatspi.ROLE_TEXT] \
+           and self._script.inDocumentContent() \
+           and not self._script.isAriaWidget(obj):
+            label = self._script.guessTheLabel(obj)
+            if label:
+                result.append(label)
 
-        # Treat ARIA widgets like default.py widgets
+        # XUL combo boxes don't always have a label for/by
+        # relationship.  But, they will make their names be
+        # the string of the thing labelling them.
         #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForText(self, obj, already_focused)
-        
-        utterances = []
-        parent = obj.parent
-        if parent.getRole() == pyatspi.ROLE_AUTOCOMPLETE:
+        if not len(result) \
+           and role == pyatspi.ROLE_COMBO_BOX \
+           and not self._script.inDocumentContent():
+            result.append(obj.name)
+
+        return result
+
+    def _getLabelAndName(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        # For radio buttons, the label is handled as a context and we
+        # assume we don't have to guess it.  If we need to guess it,
+        # we need to add it to utterances.
+        #
+        if role == pyatspi.ROLE_RADIO_BUTTON \
+           and self._script.getDisplayedLabel(obj):
+            pass
+        else:
+            result.extend(speech_generator.SpeechGenerator._getLabelAndName(
+                self, obj, **args))
+        return result
+
+    def _getLabelOrName(self, obj, **args):
+        result = []
+        if obj.parent.getRole() == pyatspi.ROLE_AUTOCOMPLETE:
             # This is the main difference between this class and the default
             # class - we'll give this thing a name here, and we'll make it
             # be the name of the autocomplete.
             #
-            label = self._script.getDisplayedLabel(parent)
-            if not label or not len(label):
-                label = parent.name
-            utterances.append(label)
-        elif obj.getRole() in [pyatspi.ROLE_ENTRY,
-                               pyatspi.ROLE_PASSWORD_TEXT] \
-            and self._script.inDocumentContent():
-            # This is a form field in web content.  If we don't get a label,
-            # we'll try to guess what text on the page is functioning as
-            # the label.
-            #
-            label = self._script.getDisplayedLabel(obj)
-            if not label or not len(label):
-                label = self._script.guessTheLabel(obj)
-            if label:
-                utterances.append(label)
+            result.extend(self._getLabelOrName(obj.parent, **args))
         else:
-            return speechgenerator.SpeechGenerator._getSpeechForText(
-                self, obj, already_focused)
-
-        if settings.presentReadOnlyText \
-           and self._script.isReadOnlyTextArea(obj):
-            utterances.append(settings.speechReadOnlyString)
-
-        utterances.extend(self.getSpeechForObjectRole(obj))
-
-        [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
-        utterances.append(text)
-
-        self._debugGenerator("Gecko._getSpeechForText",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForComboBox(self, obj, already_focused):
-        """Get the speech for a combo box.  If the combo box already has focus,
-        then only the selection is spoken.
-
-        Arguments:
-        - obj: the combo box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForComboBox(self, obj, already_focused)
-        
-        utterances = []
-
-        label = self._script.getDisplayedLabel(obj)
-        if not label:
-            if not self._script.inDocumentContent():
-                label = obj.name
-            else:
-                label = self._script.guessTheLabel(obj)
-
-        if not already_focused and label:
-            utterances.append(label)
-
-        # With Gecko, a combo box has a menu as a child.  The text being
-        # displayed for the combo box can be obtained via the selected
-        # menu item.
-        #
-        menu = None
-        for child in obj:
-            if child.getRole() == pyatspi.ROLE_MENU:
-                menu = child
-                break
-        if menu:
-            child = None
-            try:
-                # This should work...
-                #
-                child = menu.querySelection().getSelectedChild(0)
-                if not child:
-                    # It's probably a Gtk combo box.
-                    #
-                    return speechgenerator.SpeechGenerator.\
-                        _getSpeechForComboBox(self, obj, already_focused)
-            except:
-                # But just in case, we'll fall back on this.
-                # [[[TODO - JD: Will we ever have a case where the first
-                # fails, but this will succeed???]]]
-                #
-                for item in menu:
-                    if item.getState().contains(pyatspi.STATE_SELECTED):
-                        child = item
-                        break
-            if child:
-                utterances.append(child.name)
-
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        if not already_focused:
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        self._debugGenerator("Gecko._getSpeechForComboBox",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForMenuItem(self, obj, already_focused):
-        """Get the speech for a menu item.
+            result.extend(speech_generator.SpeechGenerator._getLabelOrName(
+                self, obj, **args))
+        return result
 
-        Arguments:
-        - obj: the menu item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForMenuItem(self, obj, already_focused)
-        
-        if not self._script.inDocumentContent():
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForMenuItem(self, obj, already_focused)
-
-        utterances = self._getSpeechForObjectName(obj)
+    def _getRoleName(self, obj, **args):
+        """Prevents some roles from being spoken."""
+        result = []
+        role = args.get('role', obj.getRole())
+        force = args.get('force', False)
 
         # Saying "menu item" for a combo box can confuse users. Therefore,
         # speak the combo box role instead.  Also, only do it if the menu
@@ -302,379 +180,111 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
         # navigating in the combo box)
         #
         if not obj.getState().contains(pyatspi.STATE_FOCUSED):
-            comboBox = \
-                 self._script.getAncestor(obj,
-                                          [pyatspi.ROLE_COMBO_BOX],
-                                          [pyatspi.ROLE_DOCUMENT_FRAME])
+            comboBox = self._script.getAncestor(obj,
+                                                [pyatspi.ROLE_COMBO_BOX],
+                                                [pyatspi.ROLE_DOCUMENT_FRAME])
             if comboBox:
-                utterances.extend(self.getSpeechForObjectRole(comboBox))
-
-        self._debugGenerator("Gecko._getSpeechForMenuItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForListItem(self, obj, already_focused):
-        """Get the speech for a list item.
-
-        Arguments:
-        - obj: the list item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-
-        if self._script.isAriaWidget(obj) \
-           or not self._script.inDocumentContent(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForListItem(self, obj, already_focused)
-        
-        if not obj.getState().contains(pyatspi.STATE_SELECTABLE):
-            return speechgenerator.SpeechGenerator.\
-                       _getDefaultSpeech(self, obj, already_focused)
-
-        utterances = self._getSpeechForObjectName(obj)
-
-        self._debugGenerator("Gecko._getSpeechForListItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForList(self, obj, already_focused):
-        """Get the speech for a list.
-
-        Arguments:
-        - obj: the list
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForList(self, obj, already_focused)
-        
-        if not obj.getState().contains(pyatspi.STATE_FOCUSABLE):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForList(self, obj, already_focused)
-
-        utterances = []
-
-        label = self._script.getDisplayedLabel(obj)
-        if not label:
-            if not self._script.inDocumentContent():
-                label = obj.name
-            else:
-                label = self._script.guessTheLabel(obj)
-
-        if not already_focused and label:
-            utterances.append(label)
-
-        item = None
-        selection = obj.querySelection()
-        for i in xrange(obj.childCount):
-            if selection.isChildSelected(i):
-                item = obj[i]
-                break
-        item = item or obj[0]
-        if item:
-            name = self._getSpeechForObjectName(item)
-            if name != label:
-                utterances.extend(name)
-
-        if not already_focused:
-            if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
-                # Translators: "multi-select" refers to a web form list
-                # in which more than one item can be selected at a time.
-                #
-                utterances.append(_("multi-select"))
-
-            # Translators: this represents a list in HTML.
+                return self._getRoleName(comboBox, **args)
+
+        if not force:
+            doNotSpeak = [pyatspi.ROLE_FORM,
+                          pyatspi.ROLE_LABEL,
+                          pyatspi.ROLE_MENU_ITEM,
+                          pyatspi.ROLE_PARAGRAPH,
+                          pyatspi.ROLE_SECTION,
+                          pyatspi.ROLE_UNKNOWN]
+        else:
+            # We never ever want to speak 'unknown'
             #
-            itemString = ngettext("List with %d item",
-                                  "List with %d items",
-                                  obj.childCount) % obj.childCount
-            utterances.append(itemString)
-
-        self._debugGenerator("Gecko._getSpeechForList",
-                             obj,
-                             already_focused,
-                             utterances)
+            doNotSpeak = [pyatspi.ROLE_UNKNOWN]
 
-        return utterances
-
-    def _getSpeechForImage(self, obj, already_focused):
-        """Gets a list of utterances to be spoken for an image.
-
-        The default speech will be of the following form:
-
-        label name role availability
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
+        if not force and self._script.inDocumentContent(obj):
+            doNotSpeak.append(pyatspi.ROLE_TABLE_CELL)
+            if not self._script.isAriaWidget(obj):
+                doNotSpeak.append(pyatspi.ROLE_LIST_ITEM)
+                doNotSpeak.append(pyatspi.ROLE_LIST)
 
-        Returns a list of utterances to be spoken for the object.
-        """
+        if not (role in doNotSpeak):
+            if role == pyatspi.ROLE_IMAGE:
+                link = self._script.getAncestor(obj,
+                                                [pyatspi.ROLE_LINK],
+                                                [pyatspi.ROLE_DOCUMENT_FRAME])
+                if link:
+                    result.append(rolenames.getSpeechForRoleName(link))
 
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForImage(self, obj, already_focused)
-        
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-
-            # If there's no text for the image, expose the link to
-            # the user if the image is in a link.
-            #
-            link = self._script.getAncestor(obj,
-                                            [pyatspi.ROLE_LINK],
-                                            [pyatspi.ROLE_DOCUMENT_FRAME])
-            if link:
-                if not len(utterances):
-                    return self._getSpeechForLink(link, already_focused)
+            if role == pyatspi.ROLE_HEADING:
+                level = self._script.getHeadingLevel(obj)
+                if level:
+                    # Translators: the %(level)d is in reference to a heading
+                    # level in HTML (e.g., For <h3>, the level is 3)
+                    # and the %(role)s is in reference to a previously
+                    # translated rolename for the heading.
+                    #
+                    result.append(_("%(role)s level %(level)d") % {
+                        'role': rolenames.getSpeechForRoleName(obj, role),
+                        'level': level})
                 else:
-                    utterances.extend(self.getSpeechForObjectRole(link))
-
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("Gecko._getSpeechForImage",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForLink(self, obj, already_focused):
-        """Gets a list of utterances to be spoken for a link.
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-
-            # Handle empty alt tags.
-            #
-            if name:
-                lengthOfName = len(name[0].strip())
-                if (lengthOfName > 0) and (name != label):
-                    utterances.extend(name)
-
-            # If there's no text for the link, expose part of the
-            # URI to the user.
-            #
-            if not len(utterances):
-                basename = self._script.getLinkBasename(obj)
-                if basename:
-                    utterances.append(basename)
-
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-            # If the link has a child which is an image, we want
-            # to indicate that.
-            #
-            if obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
-                utterances.extend(self.getSpeechForObjectRole(obj[0]))
-
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("Gecko._getSpeechForLink",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTable(self, obj, already_focused):
-        """Get the speech for a table
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForTable(self, obj, already_focused)
-        
-        # [[[TODO: JD - We should decide if we want to provide
-        # information about the table dimensions, whether or not
-        # this is a layout table versus a data table, etc.  For now,
-        # however, if it's in HTML content let's ignore it so that
-        # SayAll by sentence works. :-) ]]]
-        #
-        utterances = []
-
-        if not self._script.inDocumentContent():
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForTable(self, obj, already_focused)
-
-        return utterances
-
-    def _getSpeechForRadioButton(self, obj, already_focused):
-        """Get the speech for a radio button.  If the button already had
-        focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the radio button
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForRadioButton(self, obj, already_focused)
-        
-        if not self._script.inDocumentContent():
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForRadioButton(self, obj, already_focused)
-
-        utterances = []
-        if obj.getState().contains(pyatspi.STATE_CHECKED):
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            selectionState = C_("radiobutton", "selected")
-        else:
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            selectionState = C_("radiobutton", "not selected")
-
-        if not already_focused:
-            # The label is handled as a context in default.py -- assuming we
-            # don't have to guess it.  If  we need to guess it, we need to
-            # add it to utterances.
-            #
-            label = self._script.getDisplayedLabel(obj)
-            if not label:
-                label = self._script.guessTheLabel(obj)
-                if label:
-                    utterances.append(label)
-
-            utterances.append(selectionState)
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-        else:
-            utterances.append(selectionState)
-
-        self._debugGenerator("Gecko._getSpeechForRadioButton",
-                             obj,
-                             already_focused,
-                             utterances)
-        return utterances
+                    result.append(rolenames.getSpeechForRoleName(obj, role))
+            else:
+                result.append(rolenames.getSpeechForRoleName(obj, role))
 
-    def _getSpeechForCheckBox(self, obj, already_focused):
-        """Get the speech for a check box.  If the check box already had
-        focus, then only the state is spoken.
+            if role == pyatspi.ROLE_LINK \
+               and obj.childCount and obj[0].getRole() == pyatspi.ROLE_IMAGE:
+                # If this is a link with a child which is an image, we
+                # want to indicate that.
+                #
+                result.append(rolenames.getSpeechForRoleName(obj[0]))
 
-        Arguments:
-        - obj: the check box
-        - already_focused: False if object just received focus
+        return result
 
-        Returns a list of utterances to be spoken for the object.
-        """
+    def _getExpandedEOCs(self, obj, **args):
+        """Returns the expanded embedded object characters for an object."""
+        result = []
+        text = self._script.expandEOCs(obj)
+        if text:
+            result.append(text)
+        return result
 
-        # Treat ARIA widgets like default.py widgets
-        #
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForCheckBox(self, obj, already_focused)
-        
-        if not self._script.inDocumentContent():
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForCheckBox(self, obj, already_focused)
-
-        utterances = []
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_INDETERMINATE):
-            # Translators: this represents the state of a checkbox.
-            #
-            checkedState = _("partially checked")
-        elif state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this represents the state of a checkbox.
-            #
-            checkedState = _("checked")
-        else:
-            # Translators: this represents the state of a checkbox.
+    def _getNumberOfChildren(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_LIST:
+            # Translators: this represents a list in HTML.
             #
-            checkedState = _("not checked")
-
-        # If it's not already focused, say its label.
-        #
-        if not already_focused:
-            label = self._script.getDisplayedLabel(obj)
-            if not label:
-                label = self._script.guessTheLabel(obj)
-            if label:
-                utterances.append(label)
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(checkedState)
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
+            result.append(ngettext("List with %d item",
+                                   "List with %d items",
+                                   obj.childCount) % obj.childCount)
         else:
-            utterances.append(checkedState)
-
-        self._debugGenerator("Gecko._getSpeechForCheckBox",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def getSpeechContext(self, obj, stopAncestor=None):
-        """Get the speech that describes the names and role of
-        the container hierarchy of the object, stopping at and
-        not including the stopAncestor.
-
-        Arguments:
-        - obj: the object
-        - stopAncestor: the ancestor to stop at and not include (None
-          means include all ancestors)
-
-        Returns a list of utterances to be spoken.
-        """
-
-        utterances = []
-
-        if obj is stopAncestor:
-            return utterances
-
-        # Skip items of unknown rolenames, menu bars, labels with 
+            result.extend(speech_generator.SpeechGenerator._getNumberOfChildren(
+                self, obj, **args))
+        return result
+
+    def _getFocusedItem(self, obj, **args):
+        result = []
+        role = args.get('role', obj.getRole())
+        if role == pyatspi.ROLE_LIST:
+            item = None
+            selection = obj.querySelection()
+            for i in xrange(obj.childCount):
+                if selection.isChildSelected(i):
+                    item = obj[i]
+                    break
+            item = item or obj[0]
+            if item:
+                name = self._getName(item, **args)
+                if name and name != self._getLabel(obj, **args):
+                    result.extend(name)
+        return result
+
+    def _getAncestors(self, obj, **args):
+        result = []
+        priorObj = args.get('priorObj', None)
+        commonAncestor = self._script.findCommonAncestor(priorObj, obj)
+
+        if obj is commonAncestor:
+            return result
+
+        # Skip items of unknown rolenames, menu bars, labels with
         # children, and autocompletes.  (With autocompletes, we
         # wind up speaking the text object). Beginning with Firefox
         # 3.2, list items have names corresponding with their text.
@@ -702,7 +312,7 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
         parent = obj.parent
         while parent and (parent.parent != parent):
             role = parent.getRole()
-            if self._script.isSameObject(parent, stopAncestor) \
+            if self._script.isSameObject(parent, commonAncestor) \
                or role in stopRoles:
                 break
 
@@ -717,8 +327,8 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
                and parent.parent.getRole() == pyatspi.ROLE_COMBO_BOX:
                 parent = parent.parent
                 continue
-                
-            # Also skip the parent if its accessible text is a single 
+
+            # Also skip the parent if its accessible text is a single
             # EMBEDDED_OBJECT_CHARACTER: Script.getDisplayedText will
             # end up coming back to the child of an object for the text
             # if an object's text contains a single EOC. In addition,
@@ -743,65 +353,39 @@ class SpeechGenerator(speechgenerator.SpeechGenerator):
             #
             text = self._script.getDisplayedText(parent)
             label = self._script.getDisplayedLabel(parent)
-            newUtterances = []
+            newResult = []
             if text and (text != label) and len(text.strip()) \
                 and (not text.startswith("chrome://")):
-                newUtterances.append(text)
+                newResult.append(text)
             if label and len(label.strip()):
-                newUtterances.append(label)
+                newResult.append(label)
 
             # Finally add the role if it's not among the roles we don't
             # wish to speak.
             #
-            if not role in dontSpeakRoles and len(newUtterances):
-                utterances.append(rolenames.getSpeechForRoleName(parent))
+            if not (role in dontSpeakRoles) and len(newResult):
+                result.append(rolenames.getSpeechForRoleName(parent))
 
             # If this object is an ARIA widget with STATE_REQUIRED, add
             # that. (Note that for the most part, the ARIA widget itself
             # has this state, but in the case of a group of radio buttons,
             # it is the group which has the state).
             #
-            utterances.extend(self._getSpeechForRequiredObject(parent))
+            result.extend(self._getRequired(parent, **args))
 
-            utterances.extend(newUtterances)
+            result.extend(newResult)
 
             parent = parent.parent
 
-        utterances.reverse()
+        result.reverse()
 
-        return utterances
-            
-    def _getSpeechForSlider(self, obj, already_focused):
-        """Get the speech for a slider.  If the object already
-        had focus, just the value is spoken.
+        return result
 
-        Arguments:
-        - obj: the slider
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-        
-        # Let default handle non-ARIA widgets (XUL?)
-        if self._script.isAriaWidget(obj):
-            return speechgenerator.SpeechGenerator.\
-                       _getSpeechForSlider(self, obj, already_focused)
-
-        valueString = self._script.getTextForValue(obj)
-
-        if already_focused:
-            utterances = [valueString]
-        else:
-            utterances = []
-            utterances.extend(self._getSpeechForObjectLabel(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(valueString)
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("Gecko._getSpeechForSlider",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-                        
+    def getSpeech(self, obj, **args):
+        # ARIA widgets get treated like regular default widgets.
+        #
+        result = []
+        args['isAria'] = self._script.isAriaWidget(obj)
+        result = speech_generator.SpeechGenerator.getSpeech(self, obj, **args)
+        del args['isAria']
+        return result
diff --git a/src/orca/scripts/toolkits/Gecko/where_am_i.py b/src/orca/scripts/toolkits/Gecko/where_am_i.py
index 3485a15..8051465 100644
--- a/src/orca/scripts/toolkits/Gecko/where_am_i.py
+++ b/src/orca/scripts/toolkits/Gecko/where_am_i.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -26,7 +26,7 @@ http://developer.mozilla.org/en/docs/Accessibility/ATSPI_Support
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
@@ -44,7 +44,7 @@ from orca.orca_i18n import ngettext # for ngettext support
 #                                                                      #
 # Custom WhereAmI                                                      #
 #                                                                      #
-######################################################################## 
+########################################################################
 
 class GeckoWhereAmI(where_am_I.WhereAmI):
     def __init__(self, script):
@@ -54,7 +54,7 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
         """
         where_am_I.WhereAmI.__init__(self, script)
         self._script = script
-        
+
     def whereAmI(self, obj, basicOnly):
         """Calls the base class method for basic information and Gecko
         specific presentation methods for detailed/custom information.
@@ -83,14 +83,16 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
                 and not self._script.isAriaWidget(orca_state.locusOfFocus)):
             where_am_I.WhereAmI._speakDefaultButton(self, obj)
 
-    def _getSpeechForRoleName(self, obj, role=None):
+    # pylint: disable-msg=W0142
+
+    def _getSpeechForRoleName(self, obj, **args):
         """Returns the rolename to be spoken for the object. Overridden
         here because there are times when we do not want the speech
         generator returning a role to speak (e.g. navigating within
-        a document), but other times when we would (e.g. during a 
+        a document), but other times when we would (e.g. during a
         whereAmI).
         """
-
+        role = args.get('role', None)
         objRole = obj.getRole()
         if not role and objRole in [pyatspi.ROLE_DOCUMENT_FRAME,
                                     pyatspi.ROLE_FORM,
@@ -100,8 +102,9 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
                                     pyatspi.ROLE_SECTION,
                                     pyatspi.ROLE_TABLE_CELL]:
             role = objRole
-
-        return where_am_I.WhereAmI._getSpeechForRoleName(self, obj, role)
+        if role:
+            args['role'] = role
+        return where_am_I.WhereAmI._getSpeechForRoleName(self, obj, **args)
 
     def _getObjName(self, obj):
         """Returns the name to speak for an object.
@@ -147,14 +150,14 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
             speech.speak(_("image map link"))
 
     def _collectionPageSummary(self):
-        """Uses the Collection interface to get the quantity of headings, 
+        """Uses the Collection interface to get the quantity of headings,
         forms, tables, visited and unvisited links.
         """
         docframe = self._script.getDocumentFrame()
         col = docframe.queryCollection()
         # We will initialize these after the queryCollection() call in case
         # Collection is not supported
-        headings = 0 
+        headings = 0
         forms = 0
         tables = 0
         vlinks = 0
@@ -163,7 +166,7 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
         stateset = pyatspi.StateSet()
         roles = [pyatspi.ROLE_HEADING, pyatspi.ROLE_LINK, pyatspi.ROLE_TABLE,
                  pyatspi.ROLE_FORM]
-        rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+        rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                                    "", col.MATCH_NONE,
                                    roles, col.MATCH_ANY,
                                    "", col.MATCH_NONE,
@@ -188,12 +191,12 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
                     uvlinks += 1
 
         self._outputPageSummary(headings, forms, tables, vlinks, uvlinks, None)
-            
+
     def _iterativePageSummary(self, obj):
-        """Reads the quantity of headings, forms, tables, visited and 
+        """Reads the quantity of headings, forms, tables, visited and
         unvisited links.
         """
-        headings = 0 
+        headings = 0
         forms = 0
         tables = 0
         vlinks = 0
@@ -230,10 +233,10 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
         else:
             percentread = None
 
-        self._outputPageSummary(headings, forms, tables, 
+        self._outputPageSummary(headings, forms, tables,
                                vlinks, uvlinks, percentread)
 
-    def _outputPageSummary(self, headings, forms, tables, 
+    def _outputPageSummary(self, headings, forms, tables,
                                  vlinks, uvlinks, percent):
 
         utterances = []
@@ -269,11 +272,10 @@ class GeckoWhereAmI(where_am_I.WhereAmI):
                  ('%d unvisited link', '%d unvisited links', uvlinks) %uvlinks)
         if percent is not None:
             # Translators: Announces the percentage of the document that has
-            # been read.  This is calculated by knowing the index of the 
-            # current position divided by the total number of objects on the 
+            # been read.  This is calculated by knowing the index of the
+            # current position divided by the total number of objects on the
             # page.
-            # 
+            #
             utterances.append(_('%d percent of document read') %percent)
 
-        speech.speakUtterances(utterances)  
-
+        speech.speak(utterances)
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am b/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am
index e9404a6..a322361 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/Makefile.am
@@ -3,8 +3,9 @@ orca_pathdir=$(pyexecdir)
 orca_python_PYTHON = \
 	__init__.py \
 	braillegenerator.py \
+	formatting.py \
 	script.py \
-	speechgenerator.py \
+	speech_generator.py \
 	where_am_I.py
 
 orca_pythondir=$(pyexecdir)/orca/scripts/toolkits/J2SE-access-bridge
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py b/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py
index 5c2a804..325b44a 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/__init__.py
@@ -1,4 +1,4 @@
 from script import Script
-from speechgenerator import SpeechGenerator
+from speech_generator import SpeechGenerator
 from braillegenerator import BrailleGenerator
 from where_am_I import WhereAmI
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/formatting.py b/src/orca/scripts/toolkits/J2SE-access-bridge/formatting.py
new file mode 100644
index 0000000..f8c2095
--- /dev/null
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/formatting.py
@@ -0,0 +1,51 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Custom formatting for Java Swing."""
+
+__id__ = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import copy
+
+import pyatspi
+
+import orca.formatting
+
+# pylint: disable-msg=C0301
+
+formatting = {
+    'speech': {
+        # In Java, tree objects are labels, so we need to look at their
+        # states in order to tell whether they are expanded or collapsed.
+        #
+        pyatspi.ROLE_LABEL: {
+            'unfocused': '(displayedText or roleName) + expandableState',
+            'focused': 'expandableState'
+            },
+    }
+}
+
+class Formatting(orca.formatting.Formatting):
+    def __init__(self, script):
+        orca.formatting.Formatting.__init__(self, script)
+        self.update(copy.deepcopy(formatting))
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/script.py b/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
index 2aa815a..5e3a540 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2006-2008 Sun Microsystems Inc.
+# Copyright 2006-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -20,7 +20,7 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
@@ -32,7 +32,8 @@ import orca.orca_state as orca_state
 import orca.keybindings as keybindings
 
 from braillegenerator import BrailleGenerator
-from speechgenerator import SpeechGenerator
+from speech_generator import SpeechGenerator
+from formatting import Formatting
 from where_am_I import WhereAmI
 
 ########################################################################
@@ -66,6 +67,10 @@ class Script(default.Script):
         """
         return SpeechGenerator(self)
 
+    def getFormatting(self):
+        """Returns the formatting strings for this script."""
+        return Formatting(self)
+
     def consumesKeyboardEvent(self, keyboardEvent):
         """Called when a key is pressed on the keyboard.
 
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
new file mode 100644
index 0000000..5261df3
--- /dev/null
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
@@ -0,0 +1,51 @@
+# Orca
+#
+# Copyright 2006-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import orca.speechgenerator as speechgenerator
+
+########################################################################
+#                                                                      #
+# Speech Generator                                                     #
+#                                                                      #
+########################################################################
+
+class SpeechGenerator(speechgenerator.SpeechGenerator):
+
+    # pylint: disable-msg=W0142
+
+    def __init__(self, script):
+        speechgenerator.SpeechGenerator.__init__(self, script)
+
+    def _getAncestors(self, obj, **args):
+        """The Swing toolkit has labelled panels that do not implement the
+        AccessibleText interface, but getDisplayedText returns a
+        meaningful string that needs to be used if getDisplayedLabel
+        returns None.
+        """
+        args['requireText'] = False
+        result = speechgenerator.SpeechGenerator._getAncestors(
+            self, obj, **args)
+        del args['requireText']
+        return result
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py b/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
deleted file mode 100644
index 0152928..0000000
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/speechgenerator.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Orca
-#
-# Copyright 2006-2008 Sun Microsystems Inc.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA  02110-1301 USA.
-
-__id__        = "$Id$"
-__version__   = "$Revision$"
-__date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
-__license__   = "LGPL"
-
-import pyatspi
-
-import orca.rolenames as rolenames
-import orca.speechgenerator as speechgenerator
-
-from orca.orca_i18n import _ # for gettext support
-
-########################################################################
-#                                                                      #
-# Speech Generator                                                     #
-#                                                                      #
-########################################################################
-
-class SpeechGenerator(speechgenerator.SpeechGenerator):
-    def __init__(self, script):
-        speechgenerator.SpeechGenerator.__init__(self, script)
-
-    def _getSpeechForLabel(self, obj, already_focused):
-        """Get the speech for a label.
-
-        Arguments:
-        - obj: the label
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-        if (not already_focused):
-            text = self._script.getDisplayedText(obj)
-            if not text:
-                text = rolenames.getSpeechForRoleName(obj)
-            if text:
-                utterances.append(text)
-
-        # In Java, tree objects are labels, so we need to look at their
-        # states in order to tell whether they are expanded or collapsed.
-        #
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_EXPANDED):
-            # Translators: this represents the state of a node in a tree.
-            # 'expanded' means the children are showing.
-            # 'collapsed' means the children are not showing.
-            #
-            utterances.append(_("expanded"))
-        elif not state.contains(pyatspi.STATE_EXPANDED) and \
-                 state.contains(pyatspi.STATE_EXPANDABLE):
-            # Translators: this represents the state of a node in a tree.
-            # 'expanded' means the children are showing.
-            # 'collapsed' means the children are not showing.
-            #
-            utterances.append(_("collapsed"))
-
-        self._debugGenerator("J2SE-access-bridge:_getSpeechForLabel",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def getSpeechContext(self, obj, stopAncestor=None):
-        """This method is identical to speechgeneratior.getSpeechContext
-        with one exception. The following test in
-        speechgenerator.getSpeechContext:
-
-            if not text and 'Text' in pyatspi.listInterfaces(parent):
-                text = self._script.getDisplayedText(parent)
-
-        has be replaced by
-
-           if not text:
-               text = self._script.getDisplayedText(parent)
-
-        The Swing toolkit has labelled panels that do not implement the
-        AccessibleText interface, but getDisplayedText returns
-        a meaningful string that needs to be used if getDisplayedLabel
-        returns None.
-        """
-
-        utterances = []
-
-        if not obj:
-            return utterances
-
-        if obj == stopAncestor:
-            return utterances
-
-        parent = obj.parent
-        if parent \
-            and (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
-            and (parent.getRole() == pyatspi.ROLE_TABLE_CELL):
-            parent = parent.parent
-
-        while parent and (parent.parent != parent):
-            if parent == stopAncestor:
-                break
-            if not self._script.isLayoutOnly(parent):
-                text = self._script.getDisplayedLabel(parent)
-                if not text and (parent.getRole() == pyatspi.ROLE_PANEL):
-                    text = self._script.getDisplayedText(parent)
-                if text and len(text.strip()):
-                    # Push announcement of cell to the end
-                    #
-                    if parent.getRole() not in [pyatspi.ROLE_TABLE_CELL,
-                                                pyatspi.ROLE_FILLER]:
-                        utterances.append(\
-                            rolenames.getSpeechForRoleName(parent))
-                    utterances.append(text)
-                    if parent.getRole() == pyatspi.ROLE_TABLE_CELL:
-                        utterances.append(\
-                            rolenames.getSpeechForRoleName(parent))
-            parent = parent.parent
-
-        utterances.reverse()
-
-        return utterances
diff --git a/src/orca/speech.py b/src/orca/speech.py
index 53ffd92..1ef9630 100644
--- a/src/orca/speech.py
+++ b/src/orca/speech.py
@@ -137,29 +137,8 @@ def sayAll(utteranceIterator, progressCallback):
             debug.println(debug.LEVEL_INFO, logLine)
             log.info(logLine)
 
-def speak(text, acss=None, interrupt=True):
-    """Speaks all queued text immediately.  If text is not None,
-    it is added to the queue before speaking.
-
-    Arguments:
-    - text:      optional text to add to the queue before speaking
-    - acss:      acss.ACSS instance; if None,
-                 the default voice settings will be used.
-                 Otherwise, the acss settings will be
-                 used to augment/override the default
-                 voice settings.
-    - interrupt: if True, stops any speech in progress before
-                 speaking the text
-    """
-
-    # We will not interrupt a key echo in progress.
-    #
-    if orca_state.lastKeyEchoTime:
-        interrupt = interrupt \
-            and ((time.time() - orca_state.lastKeyEchoTime) > 0.5)
-
-    if settings.silenceSpeech:
-        return
+def _speak(text, acss, interrupt):
+    """Speaks the individual string using the given ACSS."""
 
     if settings.speakMultiCaseStringsAsWords:
         text = _processMultiCaseString(text)
@@ -169,12 +148,64 @@ def speak(text, acss=None, interrupt=True):
         text = _processMultiCaseString(text)
 
     logLine = "SPEECH OUTPUT: '" + text + "'"
-    debug.println(debug.LEVEL_INFO, logLine)
-    log.info(logLine)
+    extraDebug = ""
+    if acss in settings.voices.values():
+        for key in settings.voices:
+            if acss == settings.voices[key]:
+                if key != settings.DEFAULT_VOICE:
+                    extraDebug = " voice=%s" % key
+                break
+    debug.println(debug.LEVEL_INFO, logLine + extraDebug)
+    log.info(logLine + extraDebug)
 
     if _speechserver:
         _speechserver.speak(text, __resolveACSS(acss), interrupt)
 
+
+def speak(content, acss=None, interrupt=True):
+    """Speaks the given content.  The content can be either a simple
+    string or an array of arrays of objects returned by a speech
+    generator."""
+
+    # We will not interrupt a key echo in progress.
+    #
+    if orca_state.lastKeyEchoTime:
+        interrupt = interrupt \
+            and ((time.time() - orca_state.lastKeyEchoTime) > 0.5)
+
+    if settings.silenceSpeech:
+        return
+
+    if isinstance(content, basestring):
+        subString = content
+    elif isinstance(content, list):
+        subString = None
+        for element in content:
+            if isinstance(element, basestring):
+                if subString:
+                    subString += " " + element
+                else:
+                    subString = element
+            else:
+                if subString:
+                    _speak(subString, acss, interrupt)
+                subString = None
+                if isinstance(element, list):
+                    speak(element, acss, interrupt)
+                elif isinstance(element, ACSS):
+                    acss = ACSS(acss)
+                    acss.update(element)
+                else:
+                    debug.println(debug.LEVEL_WARNING,
+                                  "UNKNOWN speech element: '%s'" % element)
+    else:
+        debug.printStack(debug.LEVEL_WARNING)
+        debug.println(debug.LEVEL_WARNING, 
+                      "bad content send to speech.speak: '%s'", repr(content))
+
+    if subString:
+        _speak(subString, acss, interrupt)
+
 def speakKeyEvent(event_string, eventType):
     """Speaks a key event immediately.
 
@@ -238,47 +269,6 @@ def isSpeaking():
     else:
         return False
 
-def speakUtterances(utterances, acss=None, interrupt=True):
-    """Speaks the given list of utterances immediately.
-
-    Arguments:
-    - list:      list of strings to be spoken
-    - acss:      acss.ACSS instance; if None,
-                 the default voice settings will be used.
-                 Otherwise, the acss settings will be
-                 used to augment/override the default
-                 voice settings.
-    - interrupt: if True, stop any speech currently in progress.
-    """
-
-    # We will not interrupt a key echo in progress.
-    #
-    if orca_state.lastKeyEchoTime:
-        interrupt = interrupt \
-            and ((time.time() - orca_state.lastKeyEchoTime) > 0.5)
-
-    if settings.silenceSpeech:
-        return
-    i = 0
-    length = len(utterances)
-    while ( i < length ):
-        if settings.speakMultiCaseStringsAsWords:
-            utterances[i] = _processMultiCaseString(utterances[i])
-        if orca_state.activeScript and orca_state.usePronunciationDictionary:
-            utterances[i] = orca_state.activeScript.adjustForPronunciation(\
-                            utterances[i])
-        if settings.speakMultiCaseStringsAsWords:
-            utterances[i] = _processMultiCaseString(utterances[i])
-        logLine = "SPEECH OUTPUT: '" + utterances[i] + "'"
-        debug.println(debug.LEVEL_INFO, logLine)
-        log.info(logLine)
-        i = i + 1
-
-    if _speechserver:
-        _speechserver.speakUtterances(utterances,
-                                       __resolveACSS(acss),
-                                       interrupt)
-
 def getInfo():
     info = None
     if _speechserver:
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
new file mode 100644
index 0000000..b2302b2
--- /dev/null
+++ b/src/orca/speech_generator.py
@@ -0,0 +1,1447 @@
+# Orca
+#
+# Copyright 2005-2009 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA  02110-1301 USA.
+
+"""Utilities for obtaining speech utterances for objects.  In general,
+there probably should be a singleton instance of the SpeechGenerator
+class."""
+
+__id__        = "$Id:$"
+__version__   = "$Revision:$"
+__date__      = "$Date:$"
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import sys
+import traceback
+
+import debug
+import orca_state
+import pyatspi
+import rolenames
+import settings
+
+from orca_i18n import _         # for gettext support
+from orca_i18n import ngettext  # for ngettext support
+from orca_i18n import C_        # to provide qualified translatable strings
+
+def _formatExceptionInfo(maxTBlevel=5):
+    cla, exc, trbk = sys.exc_info()
+    excName = cla.__name__
+    try:
+        excArgs = exc.args
+    except KeyError:
+        excArgs = "<no args>"
+    excTb = traceback.format_tb(trbk, maxTBlevel)
+    return (excName, excArgs, excTb)
+
+# [[[WDW - general note -- for all the _get* methods, it would be great if
+# we could return an empty array if we can determine the method does not
+# apply to the object.  This would allow us to reduce the number of strings
+# needed in formatting.py.]]]
+
+class SpeechGenerator:
+    """Takes accessible objects and produces a string to speak for
+    those objects.  See the getSpeech method, which is the primary
+    entry point.  Subclasses can feel free to override/extend the
+    speechGenerators instance field as they see fit."""
+
+    # pylint: disable-msg=W0142
+
+    def _overrideRole(self, newRole, args):
+        """Convenience method to allow you to temporarily override the role in
+        the args dictionary.  This changes the role in args ags
+        returns the old role so you can pass it back to _restoreRole.
+        """
+        oldRole = args.get('role', None)
+        args['role'] = newRole
+        return oldRole
+
+    def _restoreRole(self, oldRole, args):
+        """Convenience method to restore the old role back in the args
+        dictionary.  The oldRole should have been obtained from
+        _overrideRole.  If oldRole is None, then the 'role' key/value
+        pair will be deleted from args.
+        """
+        if oldRole:
+            args['role'] = oldRole
+        else:
+            del args['role']
+
+    def __init__(self, script):
+        self._script = script
+        self._methodsDict = {}
+        for method in \
+            filter(lambda z: callable(z),
+                   map(lambda y: getattr(self, y).__get__(self, self.__class__),
+                       filter(lambda x: x.startswith("_get"), dir(self)))):
+            name = method.__name__[4:]
+            name = name[0].lower() + name[1:]
+            self._methodsDict[name] = method
+
+        # Verify the formatting strings are OK.  This is only
+        # for verification and does not effect the function of
+        # Orca at all.
+
+        # Populate the entire globals with empty arrays
+        # for the results of all the legal method names.
+        #
+        methods = {}
+        for key in self._methodsDict.keys():
+            methods[key] = []
+        methods['voice'] = self.voice
+        methods['obj'] = None
+        methods['role'] = None
+        methods['pyatspi'] = pyatspi
+        for roleKey in self._script.formatting["speech"]:
+            for speechKey in ["focused", "unfocused"]:
+                try:
+                    evalString = \
+                        self._script.formatting["speech"][roleKey][speechKey]
+                except:
+                    continue
+                else:
+                    if not evalString:
+                        # It's legal to have an empty string for speech.
+                        #
+                        continue
+                    while True:
+                        try:
+                            eval(evalString, methods)
+                            break
+                        except NameError:
+                            info = _formatExceptionInfo()
+                            arg = info[1][0]
+                            arg = arg.replace("name '", "")
+                            arg = arg.replace("' is not defined", "")
+                            if not self._methodsDict.has_key(arg):
+                                debug.printException(debug.LEVEL_SEVERE)
+                                debug.println(
+                                    debug.LEVEL_SEVERE,
+                                    "Unable to find function for '%s'\n" % arg)
+                            methods[arg] = []
+                        except:
+                            debug.printException(debug.LEVEL_SEVERE)
+                            debug.println(
+                                debug.LEVEL_SEVERE,
+                                "While processing '%s' '%s' '%s' '%s'" \
+                                % (roleKey, speechKey, evalString, methods))
+                            break
+
+    #####################################################################
+    #                                                                   #
+    # Name, role, and label information                                 #
+    #                                                                   #
+    #####################################################################
+
+    def _getName(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the name of the object.  If the
+        object is directly displaying any text, that text will be
+        treated as the name.  Otherwise, the accessible name of the
+        object will be used.  If there is no accessible name, then the
+        description of the object will be used.  This method will
+        return an empty array if nothing can be found.  [[[WDW - I
+        wonder if we should just have _getName, _getDescription,
+        _getDisplayedText, etc., that don't do any fallback.  Then, we
+        can allow the formatting to do the fallback (e.g.,
+        'displayedText or name or description')
+        """
+        result = []
+        name = self._script.getDisplayedText(obj)
+        if name:
+            result.append(name)
+        elif obj.description:
+            result.append(obj.description)
+        return result
+
+    def _getTextRole(self, obj, **args):
+        """A convenience method to prevent the pyatspi.ROLE_PARAGRAPH role
+        from being spoken. In the case of a pyatspi.ROLE_PARAGRAPH
+        role, an empty array will be returned. In all other cases, the
+        role name will be returned as an array of strings (and
+        possibly voice and audio specifications).  Note that a 'role'
+        attribute in args will override the accessible role of the
+        obj. [[[WDW - I wonder if this should be moved to
+        _getRoleName.  Or, maybe make a 'do not speak roles' attribute
+        of a speech generator that we can update and the user can
+        override.]]]
+        """
+        result = []
+        role = args.get('role', obj.getRole())
+        if role != pyatspi.ROLE_PARAGRAPH:
+            result.extend(self._getRoleName(obj, **args))
+        return result
+
+    def _getRoleName(self, obj, **args):
+        """Returns the role name for the object in an array of strings (and
+        possibly voice and audio specifications), with the exception
+        that the pyatspi.ROLE_UNKNOWN role will yield an empty array.
+        Note that a 'role' attribute in args will override the
+        accessible role of the obj.
+        """
+        result = []
+        role = args.get('role', obj.getRole())
+        if (role != pyatspi.ROLE_UNKNOWN):
+            result.append(rolenames.getSpeechForRoleName(obj, role))
+        return result
+
+    def getRoleName(self, obj, **args):
+        """Returns the role name for the object in an array of strings (and
+        possibly voice and audio specifications), with the exception
+        that the pyatspi.ROLE_UNKNOWN role will yield an empty array.
+        Note that a 'role' attribute in args will override the
+        accessible role of the obj.  This is provided mostly as a
+        method for scripts to call.
+        """
+        return self._getRoleName(obj, **args)
+
+    def _getLabel(self, obj, **args):
+        """Returns the label for an object as an array of strings (and
+        possibly voice and audio specifications).  The label is
+        determined by the getDisplayedLabel of the script, and an
+        empty array will be returned if no label can be found.
+        """
+        result = []
+        label = self._script.getDisplayedLabel(obj)
+        if label:
+            result = [label]
+        return result
+
+    def _getLabelAndName(self, obj, **args):
+        """Returns the label and the name as an array of strings (and possibly
+        voice and audio specifications).  The name will only be
+        present if the name is different from the label.
+        """
+        result = []
+        label = self._getLabel(obj, **args)
+        name = self._getName(obj, **args)
+        result.extend(label)
+        if not len(label):
+            result.extend(name)
+        elif len(name) and name[0] != label[0]:
+            result.extend(name)
+        return result
+
+    def _getLabelOrName(self, obj, **args):
+        """Returns the label as an array of strings (and possibly voice
+        specifications).  If the label cannot be found, the name will
+        be used instead.  If the name cannot be found, an empty array
+        will be returned.
+        """
+        result = []
+        result.extend(self._getLabel(obj, **args))
+        if not result:
+            if obj.name and (len(obj.name)):
+                result.append(obj.name)
+        return result
+
+    def _getUnrelatedLabels(self, obj, **args):
+        """Returns, as an array of strings (and possibly voice
+        specifications), all the labels which are underneath the obj's
+        hierarchy and which are not in a label for or labelled by
+        relation.
+        """
+        labels = self._script.findUnrelatedLabels(obj)
+        result = []
+        for label in labels:
+            name = self._getName(label, **args)
+            result.extend(name)
+        return result
+
+    def _getEmbedded(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) used especially for handling embedded objects.
+        This either is the label or name of the object or the name of
+        the application for the object.
+        """
+        result = self._getLabelOrName(obj, **args)
+        if not result:
+            try:
+                result.append(obj.getApplication().name)
+            except:
+                pass
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # State information                                                 #
+    #                                                                   #
+    #####################################################################
+
+    def _getCheckedState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the checked state of the
+        object.  This is typically for check boxes. [[[WDW - should we
+        return an empty array if we can guarantee we know this thing
+        is not checkable?]]]  [[[WDW - I wonder if we should put these
+        strings in settings.py.]]]
+        """
+        result = []
+        state = obj.getState()
+        if state.contains(pyatspi.STATE_INDETERMINATE):
+            # Translators: this represents the state of a checkbox.
+            #
+            result.append(_("partially checked"))
+        elif state.contains(pyatspi.STATE_CHECKED):
+            # Translators: this represents the state of a checkbox.
+            #
+            result.append(_("checked"))
+        else:
+            # Translators: this represents the state of a checkbox.
+            #
+            result.append(_("not checked"))
+        return result
+
+    def _getCellCheckedState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the checked state of the
+        object.  This is typically for check boxes that are in a
+        table. An empty array will be returned if this is not a
+        checkable cell.  [[[WDW - I wonder if we can roll this into
+        _getCheckedState somehow.]]]
+        """
+        result = []
+        try:
+            action = obj.queryAction()
+        except NotImplementedError:
+            action = None
+        if action:
+            for i in range(0, action.nActions):
+                # Translators: this is the action name for
+                # the 'toggle' action. It must be the same
+                # string used in the *.po file for gail.
+                #
+                if action.getName(i) in ["toggle", _("toggle")]:
+                    oldRole = self._overrideRole(pyatspi.ROLE_CHECK_BOX,
+                                            args)
+                    result.extend(self.getSpeech(obj, **args))
+                    self._restoreRole(oldRole, args)
+        return result
+
+    def _getRadioState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the checked state of the
+        object.  This is typically for check boxes. [[[WDW - should we
+        return an empty array if we can guarantee we know this thing
+        is not checkable?]]] [[[WDW - I wonder if we can roll this
+        into _getCheckedState somehow and provide some sort of
+        settings.py string to let you specify the wording to be used
+        for different roles.]]]
+        """
+        result = []
+        state = obj.getState()
+        if state.contains(pyatspi.STATE_CHECKED):
+            # Translators: this is in reference to a radio button being
+            # selected or not.
+            #
+            result.append(C_("radiobutton", "selected"))
+        else:
+            # Translators: this is in reference to a radio button being
+            # selected or not.
+            #
+            result.append(C_("radiobutton", "not selected"))
+        return result
+
+    def _getToggleState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the checked state of the
+        object.  This is typically for check boxes. [[[WDW - should we
+        return an empty array if we can guarantee we know this thing
+        is not checkable?]]] [[[WDW - I wonder if we can roll this
+        into _getCheckedState somehow and provide some sort of
+        settings.py string to let you specify the wording to be used
+        for different roles.]]]
+        """
+        result = []
+        state = obj.getState()
+        if state.contains(pyatspi.STATE_CHECKED) \
+           or state.contains(pyatspi.STATE_PRESSED):
+            # Translators: the state of a toggle button.
+            #
+            result.append(_("pressed"))
+        else:
+            # Translators: the state of a toggle button.
+            #
+            result.append(_("not pressed"))
+        return result
+
+    def _getExpandableState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the expanded/collapsed state of
+        an object, such as a tree node. If the object is not
+        expandable, an empty array will be returned.  [[[WDW - I
+        wonder if these strings should be placed in settings.py.]]]
+        """
+        result = []
+        state = obj.getState()
+        if state.contains(pyatspi.STATE_EXPANDABLE):
+            if state.contains(pyatspi.STATE_EXPANDED):
+                # Translators: this represents the state of a node in a tree.
+                # 'expanded' means the children are showing.
+                # 'collapsed' means the children are not showing.
+                #
+                result.append(_("expanded"))
+            else:
+                # Translators: this represents the state of a node in a tree.
+                # 'expanded' means the children are showing.
+                # 'collapsed' means the children are not showing.
+                #
+                result.append(_("collapsed"))
+        return result
+
+    def _getMultiselectableState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the multiselectable state of
+        the object.  This is typically for check boxes. If the object
+        is not multiselectable, an empty array will be returned.
+        [[[WDW - I wonder if this string should be placed in
+        settings.py.]]]
+        """
+        result = []
+        if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
+            # Translators: "multi-select" refers to a web form list
+            # in which more than one item can be selected at a time.
+            #
+            result.append(_("multi-select"))
+        return result
+
+    def _getMenuItemCheckedState(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the checked state of the menu
+        item, only if it is checked. Otherwise, and empty array will
+        be returned.  [[[WDW - I wonder if we can roll this into
+        _getCheckedState somehow.]]]
+        """
+        result = []
+        if obj.getState().contains(pyatspi.STATE_CHECKED):
+            # Translators: this represents the state of a checked menu item.
+            #
+            result.append(_("checked"))
+        return result
+
+    def _getAvailability(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the
+        grayed/sensitivity/availability state of the object, but only
+        if it is insensitive (i.e., grayed out and inactive).
+        Otherwise, and empty array will be returned.  [[[WDW - I
+        wonder if we should put this string into settings.py.]]]
+        """
+        result = []
+        if not obj.getState().contains(pyatspi.STATE_SENSITIVE):
+            # Translators: this represents an item on the screen that has
+            # been set insensitive (or grayed out).
+            #
+            result.append(_("grayed"))
+        return result
+
+    def _getRequired(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the required state of the
+        object, but only if it is required (i.e., it is in a dialog
+        requesting input and the user must give it a value).
+        Otherwise, and empty array will be returned.
+        """
+        result = []
+        if obj.getState().contains(pyatspi.STATE_REQUIRED):
+            result = [settings.speechRequiredStateString]
+        return result
+
+    def _getReadOnly(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the read only state of this
+        object, but only if it is read only (i.e., it is a text area
+        that cannot be edited).
+        """
+        result = []
+        if settings.presentReadOnlyText \
+           and self._script.isReadOnlyTextArea(obj):
+            result.append(settings.speechReadOnlyString)
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Image information                                                 #
+    #                                                                   #
+    #####################################################################
+
+    def _getImageDescription(self, obj, **args ):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the description of the image on
+        the object, if it exists.  Otherwise, an empty array is
+        returned.
+        """
+        result = []
+        try:
+            image = obj.queryImage()
+        except NotImplementedError:
+            pass
+        else:
+            description = image.imageDescription
+            if description and len(description):
+                result.append(description)
+        return result
+
+    def _getImage(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the image on the the object, if
+        it exists.  Otherwise, an empty array is returned.
+        """
+        result = []
+        try:
+            image = obj.queryImage()
+        except:
+            pass
+        else:
+            role = pyatspi.ROLE_IMAGE
+            result.extend(self.getSpeech(obj, role=role))
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Table interface information                                       #
+    #                                                                   #
+    #####################################################################
+
+    def _getRowHeader(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the row header for an object
+        that is in a table, if it exists.  Otherwise, an empty array
+        is returned.
+        """
+        result = []
+        try:
+            table = obj.parent.queryTable()
+        except:
+            pass
+        else:
+            index = self._script.getCellIndex(obj)
+            rowIndex = table.getRowAtIndex(index)
+            if rowIndex >= 0:
+                # Get the header information.  In Java Swing, the
+                # information is not exposed via the description
+                # but is instead a header object, so we fall back
+                # to that if it exists.
+                #
+                # [[[TODO: WDW - the more correct thing to do, I
+                # think, is to look at the row header object.
+                # We've been looking at the description for so
+                # long, though, that we'll give the description
+                # preference for now.]]]
+                #
+                desc = table.getRowDescription(rowIndex)
+                if not desc:
+                    header = table.getRowHeader(rowIndex)
+                    if header:
+                        desc = self._script.getDisplayedText(header)
+                if desc and len(desc):
+                    text = desc
+                    if settings.speechVerbosityLevel \
+                            == settings.VERBOSITY_LEVEL_VERBOSE:
+                        text += " " \
+                            + rolenames.rolenames[\
+                            pyatspi.ROLE_ROW_HEADER].speech
+                    result.append(text)
+        return result
+
+    def _getNewRowHeader(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the row header for an object
+        that is in a table, if it exists and if it is different from
+        the previous row header.  Otherwise, an empty array is
+        returned.  The previous row header is determined by looking at
+        the row header for the 'priorObj' attribute of the args
+        dictionary.  The 'priorObj' is typically set by Orca to be the
+        previous object with focus.
+        """
+        result = []
+        if obj:
+            priorObj = args.get('priorObj', None)
+            try:
+                priorParent = priorObj.parent
+            except:
+                priorParent = None
+
+            if (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                or (obj.parent and obj.parent.getRole() == pyatspi.ROLE_TABLE):
+                try:
+                    table = priorParent.queryTable()
+                except:
+                    table = None
+                if table \
+                   and ((priorObj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                         or (priorObj.getRole() == pyatspi.ROLE_TABLE)):
+                    index = self._script.getCellIndex(priorObj)
+                    oldRow = table.getRowAtIndex(index)
+                else:
+                    oldRow = -1
+
+                try:
+                    table = obj.parent.queryTable()
+                except:
+                    pass
+                else:
+                    index = self._script.getCellIndex(obj)
+                    newRow = table.getRowAtIndex(index)
+                    if (newRow >= 0) \
+                       and (index != newRow) \
+                       and ((newRow != oldRow) \
+                            or (obj.parent != priorParent)):
+                        result = self._getRowHeader(obj, **args)
+        return result
+
+    def _getColumnHeader(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the column header for an object
+        that is in a table, if it exists.  Otherwise, an empty array
+        is returned.
+        """
+        result = []
+        try:
+            table = obj.parent.queryTable()
+        except:
+            pass
+        else:
+            index = self._script.getCellIndex(obj)
+            columnIndex = table.getColumnAtIndex(index)
+            # Don't speak Thunderbird column headers, since
+            # it's not possible to navigate across a row.
+            # [[[TODO: WDW - move the T-bird check to the T-bird generator.]]]
+            if (columnIndex >= 0) \
+               and not self._script.getTopLevelName(obj).endswith(
+                " - Thunderbird"):
+                # Get the header information.  In Java Swing, the
+                # information is not exposed via the description
+                # but is instead a header object, so we fall back
+                # to that if it exists.
+                #
+                # [[[TODO: WDW - the more correct thing to do, I
+                # think, is to look at the row header object.
+                # We've been looking at the description for so
+                # long, though, that we'll give the description
+                # preference for now.]]]
+                #
+                desc = table.getColumnDescription(columnIndex)
+                if not desc:
+                    header = table.getColumnHeader(columnIndex)
+                    if header:
+                        desc = self._script.getDisplayedText(header)
+                if desc and len(desc):
+                    text = desc
+                    if settings.speechVerbosityLevel \
+                            == settings.VERBOSITY_LEVEL_VERBOSE:
+                        text += " " \
+                            + rolenames.rolenames[\
+                            pyatspi.ROLE_COLUMN_HEADER].speech
+                    result.append(text)
+        return result
+
+    def _getNewColumnHeader(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the column header for an object
+        that is in a table, if it exists and if it is different from
+        the previous column header.  Otherwise, an empty array is
+        returned.  The previous column header is determined by looking
+        at the column header for the 'priorObj' attribute of the args
+        dictionary.  The 'priorObj' is typically set by Orca to be the
+        previous object with focus.
+        """
+        result = []
+        if obj:
+            priorObj = args.get('priorObj', None)
+            try:
+                priorParent = priorObj.parent
+            except:
+                priorParent = None
+
+            if (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                or (obj.parent and obj.parent.getRole() == pyatspi.ROLE_TABLE):
+                try:
+                    table = priorParent.queryTable()
+                except:
+                    table = None
+                if table \
+                   and ((priorObj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                         or (priorObj.getRole() == pyatspi.ROLE_TABLE)):
+                    index = self._script.getCellIndex(priorObj)
+                    oldCol = table.getColumnAtIndex(index)
+                else:
+                    oldCol = -1
+
+                try:
+                    table = obj.parent.queryTable()
+                except:
+                    pass
+                else:
+                    index = self._script.getCellIndex(obj)
+                    newCol = table.getColumnAtIndex(index)
+                    if (newCol >= 0) \
+                       and (index != newCol) \
+                       and ((newCol != oldCol) \
+                            or (obj.parent != priorParent)):
+                        result = self._getColumnHeader(obj, **args)
+        return result
+
+    def _getTableCell2ChildLabel(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) for the label of a toggle in a table cell that
+        has a special 2 child pattern that we run into.  Otherwise, an
+        empty array is returned.
+        """
+        result = []
+
+        # If this table cell has 2 children and one of them has a
+        # 'toggle' action and the other does not, then present this
+        # as a checkbox where:
+        # 1) we get the checked state from the cell with the 'toggle' action
+        # 2) we get the label from the other cell.
+        # See Orca bug #376015 for more details.
+        #
+        if obj.childCount == 2:
+            cellOrder = []
+            hasToggle = [False, False]
+            for i, child in enumerate(obj):
+                try:
+                    action = child.queryAction()
+                except NotImplementedError:
+                    continue
+                else:
+                    for j in range(0, action.nActions):
+                        # Translators: this is the action name for
+                        # the 'toggle' action. It must be the same
+                        # string used in the *.po file for gail.
+                        #
+                        if action.getName(j) in ["toggle", _("toggle")]:
+                            hasToggle[i] = True
+                            break
+            if hasToggle[0] and not hasToggle[1]:
+                cellOrder = [ 1, 0 ]
+            elif not hasToggle[0] and hasToggle[1]:
+                cellOrder = [ 0, 1 ]
+            if cellOrder:
+                for i in cellOrder:
+                    if not hasToggle[i]:
+                        result.extend(self.getSpeech(obj[i], **args))
+        return result
+
+    def _getTableCell2ChildToggle(self, obj, **args):
+        """Returns an array of strings (and possinly voice and audio
+        specifications) for the toggle value of a toggle in a table
+        cell that has a special 2 child pattern that we run into.
+        Otherwise, an empty array is returned.
+        """
+        result = []
+
+        # If this table cell has 2 children and one of them has a
+        # 'toggle' action and the other does not, then present this
+        # as a checkbox where:
+        # 1) we get the checked state from the cell with the 'toggle' action
+        # 2) we get the label from the other cell.
+        # See Orca bug #376015 for more details.
+        #
+        if obj.childCount == 2:
+            cellOrder = []
+            hasToggle = [False, False]
+            for i, child in enumerate(obj):
+                try:
+                    action = child.queryAction()
+                except NotImplementedError:
+                    continue
+                else:
+                    for j in range(0, action.nActions):
+                        # Translators: this is the action name for
+                        # the 'toggle' action. It must be the same
+                        # string used in the *.po file for gail.
+                        #
+                        if action.getName(j) in ["toggle", _("toggle")]:
+                            hasToggle[i] = True
+                            break
+
+            if hasToggle[0] and not hasToggle[1]:
+                cellOrder = [ 1, 0 ]
+            elif not hasToggle[0] and hasToggle[1]:
+                cellOrder = [ 0, 1 ]
+            if cellOrder:
+                for i in cellOrder:
+                    if hasToggle[i]:
+                        result.extend(self.getSpeech(obj[i], **args))
+        return result
+
+    def _getRealTableCell(self, obj, **args):
+        """Orca has a feature to automatically read an entire row of a table
+        as the user arrows up/down the roles.  This leads to complexity in
+        the code.  This method is used to return an array of strings
+        (and possibly voice and audio specifications) for a single table
+        cell itself.  The string, 'blank', is added for empty cells.
+        [[[WDW - I wonder if this string and whether it is used or not
+        should be put in settings.py.]]]
+        """
+        result = []
+        oldRole = self._overrideRole('REAL_ROLE_TABLE_CELL', args)
+        result.extend(self.getSpeech(obj, **args))
+        self._restoreRole(oldRole, args)
+        if not result and settings.speakBlankLines:
+            # Translators: "blank" is a short word to mean the
+            # user has navigated to an empty line.
+            #
+            result = [_("blank")]
+        return result
+
+    def _getTableCellRow(self, obj, **args):
+        """Orca has a feature to automatically read an entire row of a table
+        as the user arrows up/down the roles.  This leads to complexity in
+        the code.  This method is used to return an array of strings
+        (and possibly voice and audio specifications) for an entire row
+        in a table if that's what the user has requested and if the row
+        has changed.  Otherwise, it will return an array for just the
+        current cell.
+        """
+        result = []
+
+        try:
+            parentTable = obj.parent.queryTable()
+        except NotImplementedError:
+            parentTable = None
+        if settings.readTableCellRow and parentTable \
+           and (not self._script.isLayoutOnly(obj.parent)):
+            parent = obj.parent
+            index = self._script.getCellIndex(obj)
+            row = parentTable.getRowAtIndex(index)
+            column = parentTable.getColumnAtIndex(index)
+
+            # This is an indication of whether we should speak all the
+            # table cells (the user has moved focus up or down a row),
+            # or just the current one (focus has moved left or right in
+            # the same row).
+            #
+            speakAll = True
+            if "lastRow" in self._script.pointOfReference \
+               and "lastColumn" in self._script.pointOfReference:
+                pointOfReference = self._script.pointOfReference
+                speakAll = \
+                    (pointOfReference["lastRow"] != row) \
+                     or ((row == 0 or row == parentTable.nRows-1) \
+                     and pointOfReference["lastColumn"] == column)
+            if speakAll:
+                for i in range(0, parentTable.nColumns):
+                    cell = parentTable.getAccessibleAt(row, i)
+                    if not cell:
+                        continue
+                    state = cell.getState()
+                    showing = state.contains(pyatspi.STATE_SHOWING)
+                    if showing:
+                        # If this table cell has a "toggle" action, and
+                        # doesn't have any label associated with it then
+                        # also speak the table column header.
+                        # See Orca bug #455230 for more details.
+                        #
+                        label = self._script.getDisplayedText(
+                            self._script.getRealActiveDescendant(cell))
+                        try:
+                            action = cell.queryAction()
+                        except NotImplementedError:
+                            action = None
+                        if action and (label == None or len(label) == 0):
+                            for j in range(0, action.nActions):
+                                # Translators: this is the action name for
+                                # the 'toggle' action. It must be the same
+                                # string used in the *.po file for gail.
+                                #
+                                if action.getName(j) in ["toggle",
+                                                         _("toggle")]:
+                                    accHeader = \
+                                        parentTable.getColumnHeader(i)
+                                    result.append(accHeader.name)
+                        result.extend(self._getRealTableCell(cell, **args))
+            else:
+                result.extend(self._getRealTableCell(obj, **args))
+        else:
+            result.extend(self._getRealTableCell(obj, **args))
+        return result
+
+    def _getUnselectedCell(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) if this is an icon within an layered pane or a
+        table cell within a table or a tree table and the item is
+        focused but not selected.  Otherwise, an empty array is
+        returned.  [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+        result = []
+
+        # If this is an icon within an layered pane or a table cell
+        # within a table or a tree table and the item is focused but not
+        # selected, let the user know. See bug #486908 for more details.
+        #
+        checkIfSelected = False
+        objRole, parentRole, state = None, None, None
+        if obj:
+            objRole = obj.getRole()
+            state = obj.getState()
+            if obj.parent:
+                parentRole = obj.parent.getRole()
+
+        if objRole == pyatspi.ROLE_TABLE_CELL \
+           and (parentRole == pyatspi.ROLE_TREE_TABLE \
+                or parentRole == pyatspi.ROLE_TABLE):
+            checkIfSelected = True
+
+        # If we met the last set of conditions, but we got here by
+        # moving left or right on the same row, then don't announce the
+        # selection state to the user. See bug #523235 for more details.
+        #
+        if checkIfSelected and orca_state.lastNonModifierKeyEvent \
+           and orca_state.lastNonModifierKeyEvent.event_string \
+               in ["Left", "Right"]:
+            checkIfSelected = False
+
+        if objRole == pyatspi.ROLE_ICON \
+           and parentRole == pyatspi.ROLE_LAYERED_PANE:
+            checkIfSelected = True
+
+        if checkIfSelected \
+           and state and not state.contains(pyatspi.STATE_SELECTED):
+            # Translators: this is in reference to a table cell being
+            # selected or not.
+            #
+            result.append(C_("tablecell", "not selected"))
+
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Terminal information                                              #
+    #                                                                   #
+    #####################################################################
+
+    def _getTerminal(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) used especially for handling terminal objects.
+        This either is the name of the frame the terminal is in or the
+        displayed label of the terminal.  [[[WDW - it might be nice
+        to return an empty array if this is not a terminal.]]]
+        """
+        result = []
+        title = None
+        frame = self._script.getFrame(obj)
+        if frame:
+            title = frame.name
+        if not title:
+            title = self._script.getDisplayedLabel(obj)
+        result.append(title)
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Text interface information                                        #
+    #                                                                   #
+    #####################################################################
+
+    def _getCurrentLineText(self, obj, **args ):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the current line of text, if
+        this is a text object.  [[[WDW - consider returning an empty
+        array if this is not a text object.]]]
+        """
+        [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
+        return [text]
+
+    def _getDisplayedText(self, obj, **args ):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents all the text being displayed
+        by the object. [[[WDW - consider returning an empty array if
+        this is not a text object.]]]
+        """
+        return [self._script.getDisplayedText(obj)]
+
+    def _getAllTextSelection(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that says if all the text for the entire
+        object is selected. [[[WDW - I wonder if this string should be
+        moved to settings.py.]]]
+        """
+        result = []
+        try:
+            textObj = obj.queryText()
+        except:
+            pass
+        else:
+            noOfSelections = textObj.getNSelections()
+            if noOfSelections == 1:
+                [string, startOffset, endOffset] = \
+                   textObj.getTextAtOffset(0, pyatspi.TEXT_BOUNDARY_LINE_START)
+                if startOffset == 0 and endOffset == len(string):
+                    # Translators: when the user selects (highlights) text in
+                    # a document, Orca lets them know this.
+                    #
+                    result = [C_("text", "selected")]
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Tree interface information                                        #
+    #                                                                   #
+    #####################################################################
+
+    def _getNodeLevel(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the tree node level of the
+        object, or an empty array if the object is not a tree
+        node. [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+        result = []
+        level = self._script.getNodeLevel(obj)
+        if level >= 0:
+            # Translators: this represents the depth of a node in a tree
+            # view (i.e., how many ancestors a node has).
+            #
+            result.append(_("tree level %d") % (level + 1))
+        return result
+
+    def _getNewNodeLevel(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the tree node level of the
+        object, or an empty array if the object is not a tree node or
+        if the node level is not different from the 'priorObj'
+        'priorObj' attribute of the args dictionary.  The 'priorObj'
+        is typically set by Orca to be the previous object with
+        focus.  [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+
+        # [[[TODO: WDW - hate duplicating code from _getNodeLevel,
+        # but don't want to call it because it will make the same
+        # self._script.getNodeLevel call again.]]]
+        #
+        result = []
+        oldLevel = self._script.getNodeLevel(args.get('priorObj', None))
+        newLevel = self._script.getNodeLevel(obj)
+        if (oldLevel != newLevel) and (newLevel >= 0):
+            # Translators: this represents the depth of a node in a tree
+            # view (i.e., how many ancestors a node has).
+            #
+            result.append(_("tree level %d") % (newLevel + 1))
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Value interface information                                       #
+    #                                                                   #
+    #####################################################################
+
+    def _getValue(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the value of the object.  This
+        is typically the numerical value, but may also be the text
+        of the 'value' attribute if it exists on the object.  [[[WDW -
+        we should consider returning an empty array if there is no
+        value.
+        """
+        return [self._script.getTextForValue(obj)]
+
+    def _getPercentage(self, obj, **args ):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the percentage value of the
+        object.  This is typically for progress bars. [[[WDW - we
+        should consider returning an empty array if there is no value.
+        """
+        result = []
+        try:
+            value = obj.queryValue()
+        except NotImplementedError:
+            pass
+        else:
+            percentValue = \
+                (value.currentValue
+                 / (value.maximumValue - value.minimumValue)) \
+                * 100.0
+            # Translators: this is the percentage value of a progress bar.
+            #
+            percentage = _("%d percent.") % percentValue + " "
+            result.append(percentage)
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Hierarchy and related dialog information                          #
+    #                                                                   #
+    #####################################################################
+
+    def _getRadioButtonGroup(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the radio button group label
+        for the object, or an empty array if the object has no such
+        label.
+        """
+        result = []
+        if obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
+            radioGroupLabel = None
+            relations = obj.getRelationSet()
+            for relation in relations:
+                if (not radioGroupLabel) \
+                    and (relation.getRelationType() \
+                         == pyatspi.RELATION_LABELLED_BY):
+                    radioGroupLabel = relation.getTarget(0)
+                    break
+            if radioGroupLabel:
+                result.append(self._script.getDisplayedText(radioGroupLabel))
+        return result
+
+    def _getNewRadioButtonGroup(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the radio button group label
+        of the object, or an empty array if the object has no such
+        label or if the radio button group is not different from the
+        'priorObj' 'priorObj' attribute of the args dictionary.  The
+        'priorObj' is typically set by Orca to be the previous object
+        with focus.
+        """
+        # [[[TODO: WDW - hate duplicating code from _getRadioButtonGroup
+        # but don't want to call it because it will make the same
+        # AT-SPI method calls.]]]
+        #
+        result = []
+        priorObj = args.get('priorObj', None)
+        if obj and obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
+            radioGroupLabel = None
+            inSameGroup = False
+            relations = obj.getRelationSet()
+            for relation in relations:
+                if (not radioGroupLabel) \
+                    and (relation.getRelationType() \
+                         == pyatspi.RELATION_LABELLED_BY):
+                    radioGroupLabel = relation.getTarget(0)
+                if (not inSameGroup) \
+                    and (relation.getRelationType() \
+                         == pyatspi.RELATION_MEMBER_OF):
+                    for i in range(0, relation.getNTargets()):
+                        target = relation.getTarget(i)
+                        if target == priorObj:
+                            inSameGroup = True
+                            break
+            if (not inSameGroup) and radioGroupLabel:
+                result.append(self._script.getDisplayedText(radioGroupLabel))
+        return result
+
+    def _getRealActiveDescendantDisplayedText(self, obj, **args ):
+        """Objects, such as tables and trees, can represent individual cells
+        via a complicated nested hierarchy.  This method returns an
+        array of strings (and possibly voice and audio specifications)
+        that represents the text actually being painted in the cell,
+        if it can be found.  Otherwise, an empty array is returned.
+        """
+        result = []
+        text = self._script.getDisplayedText(
+          self._script.getRealActiveDescendant(obj))
+        if text:
+            result = [text]
+        return result
+
+    def _getNumberOfChildren(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represents the number of children the
+        object has.  [[[WDW - can we always return an empty array if
+        this doesn't apply?]]] [[[WDW - I wonder if this string should
+        be moved to settings.py.]]]
+        """
+        result = []
+        childNodes = self._script.getChildNodes(obj)
+        children = len(childNodes)
+        if children:
+            # Translators: this is the number of items in a layered
+            # pane or table.
+            #
+            itemString = ngettext("%d item", "%d items", children) % children
+            result.append(itemString)
+        return result
+
+    def _getNoShowingChildren(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that says if this object has no showing
+        children (e.g., it's an empty table or list).  object has.
+        [[[WDW - can we always return an empty array if this doesn't
+        apply?]]] [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+        result = []
+        hasItems = False
+        for child in obj:
+            state = child.getState()
+            if state.contains(pyatspi.STATE_SHOWING):
+                hasItems = True
+                break
+        if not hasItems:
+            # Translators: this is the number of items in a layered pane
+            # or table.
+            #
+            result.append(_("0 items"))
+        return result
+
+    def _getNoChildren(self, obj, **args ):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that says if this object has no children at
+        all (e.g., it's an empty table or list).  object has.  [[[WDW
+        - can we always return an empty array if this doesn't
+        apply?]]] [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+        result = []
+        if not obj.childCount:
+            # Translators: this is the number of items in a layered pane
+            # or table.
+            #
+            result.append(_("0 items"))
+        return result
+
+    def _getUnfocusedDialogCount(self, obj,  **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that says how many unfocused alerts and
+        dialogs are associated with the application for this object.
+        [[[WDW - I wonder if this string should be moved to
+        settings.py.]]]
+        """
+        result = []
+        # If this application has more than one unfocused alert or
+        # dialog window, then speak '<m> unfocused dialogs'
+        # to let the user know.
+        #
+        alertAndDialogCount = \
+            self._script.getUnfocusedAlertAndDialogCount(obj)
+        if alertAndDialogCount > 0:
+            # Translators: this tells the user how many unfocused
+            # alert and dialog windows that this application has.
+            #
+            result.append(ngettext("%d unfocused dialog",
+                            "%d unfocused dialogs",
+                            alertAndDialogCount) % alertAndDialogCount)
+        return result
+
+    def _getAncestors(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the text of the ancestors for
+        the object.  This is typically used to present the context for
+        an object (e.g., the names of the window, the panels, etc.,
+        that the object is contained in).  If the 'priorObj' attribute
+        of the args dictionary is set, only the differences in
+        ancestry between the 'priorObj' and the current obj will be
+        computed.  The 'priorObj' is typically set by Orca to be the
+        previous object with focus.
+        """
+        result = []
+        priorObj = args.get('priorObj', None)
+        requireText = args.get('requireText', True)
+        commonAncestor = self._script.findCommonAncestor(priorObj, obj)
+        if obj != commonAncestor:
+            parent = obj.parent
+            if parent \
+                and (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
+                and (parent.getRole() == pyatspi.ROLE_TABLE_CELL):
+                parent = parent.parent
+            while parent and (parent.parent != parent):
+                if parent == commonAncestor:
+                    break
+                if not self._script.isLayoutOnly(parent):
+                    text = self._script.getDisplayedLabel(parent)
+                    if not text \
+                       and (not requireText \
+                            or (requireText \
+                                and 'Text' in pyatspi.listInterfaces(parent))):
+                        text = self._script.getDisplayedText(parent)
+                    if text and len(text.strip()):
+                        # Push announcement of cell to the end
+                        #
+                        if parent.getRole() not in [pyatspi.ROLE_TABLE_CELL,
+                                                    pyatspi.ROLE_FILLER]:
+                            result.extend(self._getRoleName(parent))
+                        result.append(text)
+                        if parent.getRole() == pyatspi.ROLE_TABLE_CELL:
+                            result.extend(self._getRoleName(parent))
+                parent = parent.parent
+        return result.reverse() or result
+
+    def _getNewAncestors(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the text of the ancestors for
+        the object.  This is typically used to present the context for
+        an object (e.g., the names of the window, the panels, etc.,
+        that the object is contained in).  If the 'priorObj' attribute
+        of the args dictionary is set, only the differences in
+        ancestry between the 'priorObj' and the current obj will be
+        computed.  Otherwise, no ancestry will be computed.  The
+        'priorObj' is typically set by Orca to be the previous object
+        with focus.
+        """
+        result = []
+        if args.get('priorObj', None):
+            result = self._getAncestors(obj, **args)
+        return result
+
+    #####################################################################
+    #                                                                   #
+    # Keyboard shortcut information                                     #
+    #                                                                   #
+    #####################################################################
+
+    def _getAccelerator(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the accelerator for the object,
+        or an empty array if no accelerator can be found.
+        """
+        result = []
+        [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
+        if accelerator:
+            # Add punctuation for better prosody.
+            #
+            #if result:
+            #    result[-1] += "."
+            result.append(accelerator)
+        return result
+
+    def _getMnemonic(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the mnemonic for the object, or
+        an empty array if no mnemonic can be found.
+        """
+        result = []
+        [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
+        if mnemonic:
+            mnemonic = mnemonic[-1] # we just want a single character
+        if not mnemonic and shortcut:
+            mnemonic = shortcut
+        if mnemonic:
+            # Add punctuation for better prosody.
+            #
+            #if result:
+            #    utterances[-1] += "."
+            result = [mnemonic]
+        return result
+
+
+    #####################################################################
+    #                                                                   #
+    # Tutorial information                                              #
+    #                                                                   #
+    #####################################################################
+
+    def _getTutorial(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the tutorial for the object.
+        The tutorial will only be generated if the user has requested
+        tutorials, and will then be generated according to the
+        tutorial generator.  A tutorial can be forced by setting the
+        'forceMessage' attribute of the args dictionary to True.
+        """
+        already_focused = args.get('already_focused', False)
+        forceMessage = args.get('forceMessage', False)
+        return self._script.tutorialGenerator.getTutorial(
+            obj,
+            already_focused,
+            forceMessage)
+
+    #####################################################################
+    #                                                                   #
+    # Tie it all together                                               #
+    #                                                                   #
+    #####################################################################
+
+    def voice(self, key=None):
+        """Returns an array containing a voice.  The key is a value
+        to be used to look up the voice in the settings.py:voices
+        dictionary.
+        """
+        try:
+            voice = settings.voices[key]
+        except:
+            voice = settings.voices[settings.DEFAULT_VOICE]
+        return [voice]
+
+    def getSpeech(self, obj, **args):
+        """Returns an array of strings (and possibly voice and audio
+        specifications) that represent the complete speech for the
+        object.  The speech to be generated depends highly upon the
+        speech formatting strings in formatting.py.
+        """
+        result = []
+        methods = {}
+        methods['voice'] = self.voice
+        methods['obj'] = obj
+        methods['pyatspi'] = pyatspi
+        methods['role'] = args.get('role', obj.getRole())
+
+        try:
+            # We sometimes want to override the role.  We'll keep the
+            # role in the args dictionary as a means to let us do so.
+            #
+            args['role'] = methods['role']
+
+            # We loop through the format string, catching each error
+            # as we go.  Each error should always be a NameError,
+            # where the name is the name of one of our generator
+            # functions.  When we encounter this, we call the function
+            # and get its results, placing them in the globals for the
+            # the call to eval.
+            #
+            format = self._script.formatting.getFormat('speech',
+                                                       **args)
+
+            # Add in the speech context if this is the first time
+            # we've been called.
+            #
+            if not args.get('recursing', False):
+                prefix = self._script.formatting.getPrefix('speech',
+                                                           **args)
+                suffix = self._script.formatting.getSuffix('speech',
+                                                           **args)
+                format = '%s + %s + %s' % (prefix, format, suffix)
+                debug.println(debug.LEVEL_ALL, "getSpeech for %s using '%s'" \
+                              % (repr(args), format))
+                args['recursing'] = True
+                firstTimeCalled = True
+            else:
+                firstTimeCalled = False
+
+            assert(format)
+            while True:
+                try:
+                    result = eval(format, methods)
+                    break
+                except NameError:
+                    result = []
+                    info = _formatExceptionInfo()
+                    arg = info[1][0]
+                    arg = arg.replace("name '", "")
+                    arg = arg.replace("' is not defined", "")
+                    if not self._methodsDict.has_key(arg):
+                        debug.printException(debug.LEVEL_SEVERE)
+                        debug.println(
+                            debug.LEVEL_SEVERE,
+                            "Unable to find function for '%s'\n" % arg)
+                        break
+                    methods[arg] = self._methodsDict[arg](obj, **args)
+                    debug.println(debug.LEVEL_ALL,
+                                  "%s=%s" % (arg, repr(methods[arg])))
+        except:
+            debug.printException(debug.LEVEL_SEVERE)
+            result = []
+
+        if firstTimeCalled:
+            debug.println(debug.LEVEL_ALL,
+                          "getSpeech generated '%s'" % repr(result))
+        return result
diff --git a/src/orca/speechgenerator.py b/src/orca/speechgenerator.py
deleted file mode 100644
index 90a56b4..0000000
--- a/src/orca/speechgenerator.py
+++ /dev/null
@@ -1,1927 +0,0 @@
-# Orca
-#
-# Copyright 2005-2008 Sun Microsystems Inc.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA  02110-1301 USA.
-
-"""Utilities for obtaining speech utterances for objects.  In general,
-there probably should be a singleton instance of the SpeechGenerator
-class.  For those wishing to override the speech generators, however,
-one can create a new instance and replace/extend the speech generators
-as they see fit."""
-
-__id__        = "$Id$"
-__version__   = "$Revision$"
-__date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
-__license__   = "LGPL"
-
-import pyatspi
-import debug
-import orca_state
-import rolenames
-import settings
-
-from orca_i18n import _         # for gettext support
-from orca_i18n import ngettext  # for ngettext support
-from orca_i18n import C_        # to provide qualified translatable strings
-
-class SpeechGenerator:
-    """Takes accessible objects and produces a string to speak for
-    those objects.  See the getSpeech method, which is the primary
-    entry point.  Subclasses can feel free to override/extend the
-    speechGenerators instance field as they see fit."""
-
-    def __init__(self, script):
-
-        # The script that created us.  This allows us to ask the
-        # script for information if we need it.
-        #
-        self._script = script
-
-        # Set up a dictionary that maps role names to functions
-        # that generate speech for objects that implement that role.
-        #
-        self.speechGenerators = {}
-        self.speechGenerators[pyatspi.ROLE_ALERT]               = \
-             self._getSpeechForAlert
-        self.speechGenerators[pyatspi.ROLE_ANIMATION]           = \
-             self._getSpeechForAnimation
-        self.speechGenerators[pyatspi.ROLE_ARROW]               = \
-             self._getSpeechForArrow
-        self.speechGenerators[pyatspi.ROLE_CHECK_BOX]           = \
-             self._getSpeechForCheckBox
-        self.speechGenerators[pyatspi.ROLE_CHECK_MENU_ITEM]     = \
-             self._getSpeechForCheckMenuItem
-        self.speechGenerators[pyatspi.ROLE_COLUMN_HEADER]       = \
-             self._getSpeechForColumnHeader
-        self.speechGenerators[pyatspi.ROLE_COMBO_BOX]           = \
-             self._getSpeechForComboBox
-        self.speechGenerators[pyatspi.ROLE_DESKTOP_ICON]        = \
-             self._getSpeechForDesktopIcon
-        self.speechGenerators[pyatspi.ROLE_DIAL]                = \
-             self._getSpeechForDial
-        self.speechGenerators[pyatspi.ROLE_DIALOG]              = \
-             self._getSpeechForDialog
-        self.speechGenerators[pyatspi.ROLE_DIRECTORY_PANE]      = \
-             self._getSpeechForDirectoryPane
-        self.speechGenerators[pyatspi.ROLE_EMBEDDED]            = \
-             self._getSpeechForEmbedded
-        self.speechGenerators[pyatspi.ROLE_FRAME]               = \
-             self._getSpeechForFrame
-        self.speechGenerators[pyatspi.ROLE_HTML_CONTAINER]      = \
-             self._getSpeechForHtmlContainer
-        self.speechGenerators[pyatspi.ROLE_ICON]                = \
-             self._getSpeechForIcon
-        self.speechGenerators[pyatspi.ROLE_IMAGE]               = \
-             self._getSpeechForImage
-        self.speechGenerators[pyatspi.ROLE_LABEL]               = \
-             self._getSpeechForLabel
-        self.speechGenerators[pyatspi.ROLE_LAYERED_PANE]        = \
-             self._getSpeechForLayeredPane
-        self.speechGenerators[pyatspi.ROLE_LIST]                = \
-             self._getSpeechForList
-        self.speechGenerators[pyatspi.ROLE_LIST_ITEM]           = \
-             self._getSpeechForListItem
-        self.speechGenerators[pyatspi.ROLE_MENU]                = \
-             self._getSpeechForMenu
-        self.speechGenerators[pyatspi.ROLE_MENU_BAR]            = \
-             self._getSpeechForMenuBar
-        self.speechGenerators[pyatspi.ROLE_MENU_ITEM]           = \
-             self._getSpeechForMenuItem
-        self.speechGenerators[pyatspi.ROLE_OPTION_PANE]         = \
-             self._getSpeechForOptionPane
-        self.speechGenerators[pyatspi.ROLE_PAGE_TAB]            = \
-             self._getSpeechForPageTab
-        self.speechGenerators[pyatspi.ROLE_PAGE_TAB_LIST]       = \
-             self._getSpeechForPageTabList
-        self.speechGenerators[pyatspi.ROLE_PARAGRAPH]           = \
-             self._getSpeechForText
-        self.speechGenerators[pyatspi.ROLE_PASSWORD_TEXT]       = \
-             self._getSpeechForText
-        self.speechGenerators[pyatspi.ROLE_PROGRESS_BAR]        = \
-             self._getSpeechForProgressBar
-        self.speechGenerators[pyatspi.ROLE_PUSH_BUTTON]         = \
-             self._getSpeechForPushButton
-        self.speechGenerators[pyatspi.ROLE_RADIO_BUTTON]        = \
-             self._getSpeechForRadioButton
-        self.speechGenerators[pyatspi.ROLE_RADIO_MENU_ITEM]     = \
-             self._getSpeechForRadioMenuItem
-        self.speechGenerators[pyatspi.ROLE_ROW_HEADER]          = \
-             self._getSpeechForRowHeader
-        self.speechGenerators[pyatspi.ROLE_SCROLL_BAR]          = \
-             self._getSpeechForScrollBar
-        self.speechGenerators[pyatspi.ROLE_SLIDER]              = \
-             self._getSpeechForSlider
-        self.speechGenerators[pyatspi.ROLE_SPIN_BUTTON]         = \
-             self._getSpeechForSpinButton
-        self.speechGenerators[pyatspi.ROLE_SPLIT_PANE]          = \
-             self._getSpeechForSplitPane
-        self.speechGenerators[pyatspi.ROLE_TABLE]               = \
-             self._getSpeechForTable
-        self.speechGenerators[pyatspi.ROLE_TABLE_CELL]          = \
-             self._getSpeechForTableCellRow
-        self.speechGenerators[pyatspi.ROLE_TABLE_COLUMN_HEADER] = \
-             self._getSpeechForTableColumnHeader
-        self.speechGenerators[pyatspi.ROLE_TABLE_ROW_HEADER]    = \
-             self._getSpeechForTableRowHeader
-        self.speechGenerators[pyatspi.ROLE_TEAROFF_MENU_ITEM]  = \
-             self._getSpeechForMenu
-        self.speechGenerators[pyatspi.ROLE_TERMINAL]            = \
-             self._getSpeechForTerminal
-        self.speechGenerators[pyatspi.ROLE_TEXT]                = \
-             self._getSpeechForText
-        self.speechGenerators[pyatspi.ROLE_TOGGLE_BUTTON]       = \
-             self._getSpeechForToggleButton
-        self.speechGenerators[pyatspi.ROLE_TOOL_BAR]            = \
-             self._getSpeechForToolBar
-        self.speechGenerators[pyatspi.ROLE_TREE]                = \
-             self._getSpeechForTable
-        self.speechGenerators[pyatspi.ROLE_TREE_TABLE]          = \
-             self._getSpeechForTable
-        self.speechGenerators[pyatspi.ROLE_WINDOW]              = \
-             self._getSpeechForWindow
-
-    def _addSpeechForObjectAccelerator(self, obj, utterances):
-        """Adds an utterance that describes the keyboard accelerator for the
-        given object to the list of utterances passed in.
-
-        Arguments:
-        - obj: the Accessible object
-        - utterances: the list of utterances to add to.
-
-        Returns a list of utterances to be spoken.
-        """
-
-        if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE:
-            [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
-            if accelerator:
-                # Add punctuation for better prosody.
-                #
-                #if utterances:
-                #    utterances[-1] += "."
-                utterances.append(accelerator)
-
-    def _addSpeechForObjectMnemonic(self, obj, utterances):
-        """Adds an utterance that describes the mnemonic for the given object
-        to the utterances passed in.
-
-        Arguments:
-        - obj: the Accessible object
-        - utterances: the list of utterances to add to.
-        """
-
-        if settings.enableMnemonicSpeaking:
-            # The mnemonic is what we're really looking for.  But,
-            # some objects (e.g., menu items) only expose the mnemonic
-            # via the full shortcut (e.g., "Alt f c" for a "Close"
-            # menu item).  So, we fall back to the last character in
-            # the shortcut if the shortcut exists.
-            #
-            [mnemonic, shortcut, accelerator] = self._script.getKeyBinding(obj)
-            if mnemonic:
-                mnemonic = mnemonic[-1] # we just want a single character
-            if not mnemonic and shortcut:
-                mnemonic = shortcut
-            if mnemonic:
-                # Add punctuation for better prosody.
-                #
-                #if utterances:
-                #    utterances[-1] += "."
-                utterances.append(mnemonic)
-
-    def _getSpeechForObjectAvailability(self, obj):
-        """Returns a list of utterances that describes the availability
-        of the given object.
-
-        Arguments:
-        - obj: the Accessible object
-
-        Returns a list of utterances to be spoken.
-        """
-        state = obj.getState()
-        if not state.contains(pyatspi.STATE_SENSITIVE):
-            # Translators: this represents an item on the screen that has
-            # been set insensitive (or grayed out).
-            #
-            return [_("grayed")]
-        else:
-            return []
-
-    def _getSpeechForObjectLabel(self, obj):
-        label = self._script.getDisplayedLabel(obj)
-        if label:
-            return [label]
-        else:
-            return []
-
-    def _getSpeechForObjectName(self, obj):
-        name = self._script.getDisplayedText(obj)
-        if name:
-            return [name]
-        elif obj.description:
-            return [obj.description]
-        else:
-            return []
-
-    def getSpeechForObjectRole(self, obj, role=None):
-        if (obj.getRole() != pyatspi.ROLE_UNKNOWN):
-            return [rolenames.getSpeechForRoleName(obj, role)]
-        else:
-            return []
-
-    def _getSpeechForAllTextSelection(self, obj):
-        """Check if this object has text associated with it and it's 
-        completely selected.
-
-        Arguments:
-        - obj: the object being presented
-        """
-
-        utterance = []
-        try:
-            textObj = obj.queryText()
-        except:
-            pass
-        else:
-            noOfSelections = textObj.getNSelections()
-            if noOfSelections == 1:
-                [string, startOffset, endOffset] = \
-                   textObj.getTextAtOffset(0, pyatspi.TEXT_BOUNDARY_LINE_START)
-                if startOffset == 0 and endOffset == len(string):
-                    # Translators: when the user selects (highlights) text in
-                    # a document, Orca lets them know this.
-                    #
-                    utterance = [C_("text", "selected")]
-
-        return utterance
-
-    def _getSpeechForRequiredObject(self, obj):
-        """Returns the list of utterances that describe the required state
-        of the given object.
-
-        Arguments:
-        - obj: the Accessible object
-
-        Returns a list of utterances to be spoken.
-        """
-
-        if not settings.presentRequiredState:
-            return []
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_REQUIRED):
-            return [settings.speechRequiredStateString]
-        else:
-            return []
-
-    def _debugGenerator(self, generatorName, obj, already_focused, utterances):
-        """Prints debug.LEVEL_FINER information regarding the speech generator.
-
-        Arguments:
-        - generatorName: the name of the generator
-        - obj: the object being presented
-        - already_focused: False if object just received focus
-        - utterances: the generated text
-        """
-
-        debug.println(debug.LEVEL_FINER,
-                      "GENERATOR: %s" % generatorName)
-        debug.println(debug.LEVEL_FINER,
-                      "           obj             = %s" % obj.name)
-        debug.println(debug.LEVEL_FINER,
-                      "           role            = %s" % obj.getRoleName())
-        debug.println(debug.LEVEL_FINER,
-                      "           already_focused = %s" % already_focused)
-        debug.println(debug.LEVEL_FINER,
-                      "           utterances:")
-        for text in utterances:
-            debug.println(debug.LEVEL_FINER,
-                      "               (%s)" % text)
-
-    def _getDefaultSpeech(self, obj, already_focused, role=None):
-        """Gets a list of utterances to be spoken for the current
-        object's name, role, and any accelerators.  This is usually the
-        fallback speech generator should no other specialized speech
-        generator exist for this object.
-
-        The default speech will be of the following form:
-
-        label name role availability mnemonic
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-        - role: A role that should be used instead of the Accessible's 
-          possible role.
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self._getSpeechForAllTextSelection(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj, role))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            if obj == orca_state.locusOfFocus:
-                self._addSpeechForObjectMnemonic(obj, utterances)
-
-        self._debugGenerator("_getDefaultSpeech",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForAlert(self, obj, already_focused):
-        """Gets the title of the dialog and the contents of labels inside the
-        dialog that are not associated with any other objects.
-
-        Arguments:
-        - obj: the Accessible dialog
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances be spoken.
-        """
-
-        utterances = []
-        label = self._getSpeechForObjectLabel(obj)
-        utterances.extend(label)
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-
-        # Find all the unrelated labels in the dialog and speak them.
-        #
-        labels = self._script.findUnrelatedLabels(obj)
-        for label in labels:
-            name = self._getSpeechForObjectName(label)
-            utterances.extend(name)
-
-        self._debugGenerator("_getSpeechForAlert",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForAnimation(self, obj, already_focused):
-        """Gets the speech for an animation.
-
-        Arguments:
-        - obj: the animation
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken.
-        """
-
-        utterances = []
-        label = self._getSpeechForObjectLabel(obj)
-        utterances.extend(label)
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-
-        self._debugGenerator("_getSpeechForAnimation",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForArrow(self, obj, already_focused):
-        """Gets a list of utterances to be spoken for an arrow.
-
-        Arguments:
-        - obj: the arrow
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: determine orientation of arrow.  Logged as bugzilla bug
-        # 319744.]]]
-        # text = arrow direction (left, right, up, down)
-        #
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForArrow",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForCheckBox(self, obj, already_focused):
-        """Get the speech for a check box.  If the check box already had
-        focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the check box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_INDETERMINATE):
-            # Translators: this represents the state of a checkbox.
-            #
-            checkedState = _("partially checked")
-        elif state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this represents the state of a checkbox.
-            #
-            checkedState = _("checked")
-        else:
-            # Translators: this represents the state of a checkbox.
-            #
-            checkedState = _("not checked")
-
-        # If it's not already focused, say it's name
-        #
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            if obj.getRole() == pyatspi.ROLE_TABLE_CELL:
-                utterances.extend(
-                  self.getSpeechForObjectRole(
-                    obj, pyatspi.ROLE_CHECK_BOX))
-            else:
-                utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(checkedState)
-            utterances.extend(self._getSpeechForRequiredObject(obj))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-        else:
-            utterances.append(checkedState)
-
-        self._debugGenerator("_getSpeechForCheckBox",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForCheckMenuItem(self, obj, already_focused):
-        """Get the speech for a check menu item.  If the check menu item
-        already had focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the check menu item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getSpeechForCheckBox(obj, already_focused)
-
-        if not already_focused:
-            self._addSpeechForObjectAccelerator(obj, utterances)
-
-        self._debugGenerator("_getSpeechForCheckMenuItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForColumnHeader(self, obj, already_focused):
-        """Get the speech for a column header.
-
-        Arguments:
-        - obj: the column header
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForColumnHeader",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForComboBox(self, obj, already_focused):
-        """Get the speech for a combo box.  If the combo box already has focus,
-        then only the selection is spoken.
-
-        Arguments:
-        - obj: the combo box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-        else:
-            label = None
-
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-
-        if not already_focused:
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        for child in obj:
-            if child.getRole() == pyatspi.ROLE_TEXT:
-                utterances.extend(self._getSpeechForAllTextSelection(child))
-
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-        self._addSpeechForObjectMnemonic(obj, utterances)
-
-        self._debugGenerator("_getSpeechForComboBox",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForDesktopIcon(self, obj, already_focused):
-        """Get the speech for a desktop icon.
-
-        Arguments:
-        - obj: the desktop icon
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForDesktopIcon",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForDial(self, obj, already_focused):
-        """Get the speech for a dial.
-
-        Arguments:
-        - obj: the dial
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: WDW - might need to include the value here?  Logged as
-        # bugzilla bug 319746.]]]
-        #
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForDial",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForDialog(self, obj, already_focused):
-        """Get the speech for a dialog box.
-
-        Arguments:
-        - obj: the dialog box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getSpeechForAlert(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForDialog",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForDirectoryPane(self, obj, already_focused):
-        """Get the speech for a directory pane.
-
-        Arguments:
-        - obj: the dial
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForDirectoryPane",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForEmbedded(self, obj, already_focused, role=None):
-        """Gets a list of utterances to be spoken for the current
-        embedded component (i.e., something in a panel).
-
-        Arguments:
-        - obj: an Accessible
-        - already_focused: False if object just received focus
-        - role: A role that should be used instead of the Accessible's 
-          possible role.
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        label = self._getSpeechForObjectLabel(obj)
-        utterances.extend(label)
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-        if not utterances:
-            try:
-                utterances.append(obj.getApplication().name)
-            except:
-                pass
-
-        self._debugGenerator("_getSpeechForEmbedded",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForFrame(self, obj, already_focused):
-        """Get the speech for a frame.
-
-        Arguments:
-        - obj: the frame
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self._getSpeechForAllTextSelection(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-            # If this application has more than one unfocused alert or
-            # dialog window, then speak '<m> unfocused dialogs'
-            # to let the user know.
-            #
-            alertAndDialogCount = \
-                        self._script.getUnfocusedAlertAndDialogCount(obj)
-            if alertAndDialogCount > 0:
-                # Translators: this tells the user how many unfocused
-                # alert and dialog windows that this application has.
-                #
-                line = ngettext("%d unfocused dialog",
-                                "%d unfocused dialogs",
-                                alertAndDialogCount) % alertAndDialogCount
-                utterances.append(line)
-
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("_getSpeechForFrame",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForHtmlContainer(self, obj, already_focused):
-        """Get the speech for an HTML container.
-
-        Arguments:
-        - obj: the dial
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForHtmlContainer",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForIcon(self, obj, already_focused):
-        """Get the speech for an icon.
-
-        Arguments:
-        - obj: the icon
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: WDW - HACK to remove availability output because nautilus
-        # doesn't include this information for desktop icons.  If, at some
-        # point, it is determined that availability should be added back in,
-        # then a custom script for nautilus needs to be written to remove the
-        # availability.]]]
-        #
-        utterances = []
-        label = self._getSpeechForObjectLabel(obj)
-        utterances.extend(label)
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-        
-        try:
-            image = obj.queryImage()
-        except NotImplementedError:
-            pass
-        else:
-            description = image.imageDescription
-            if description and len(description):
-                utterances.append(description)
-
-        if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE:
-            utterances.append(
-              rolenames.getSpeechForRoleName(
-                obj, pyatspi.ROLE_ICON))
-
-        self._debugGenerator("_getSpeechForIcon",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForImage(self, obj, already_focused):
-        """Get the speech for an image.
-
-        Arguments:
-        - obj: the image
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(
-            obj, already_focused, pyatspi.ROLE_IMAGE)
-
-        self._debugGenerator("_getSpeechForImage",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForLabel(self, obj, already_focused):
-        """Get the speech for a label.
-
-        Arguments:
-        - obj: the label
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForLabel",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForLayeredPane(self, obj, already_focused):
-        """Get the speech for a layered pane
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForLayeredPane",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        # If this has no children, then let the user know.
-        #
-        hasItems = False
-        for child in obj:
-            state = child.getState()
-            if state.contains(pyatspi.STATE_SHOWING):
-                hasItems = True
-                break
-        if not hasItems:
-            # Translators: this is the number of items in a layered pane
-            # or table.
-            #
-            utterances.append(_("0 items"))
-
-        return utterances
-
-    def _getSpeechForList(self, obj, already_focused):
-        """Get the speech for a list.
-
-        Arguments:
-        - obj: the list
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: WDW - include how many items in the list?
-        # Logged as bugzilla bug 319749.]]]
-        #
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForList",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-    
-    def _getSpeechForListItem(self, obj, already_focused):
-        """Get the speech for a listitem.
-
-        Arguments:
-        - obj: the listitem
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self._getSpeechForAllTextSelection(obj))
-
-        # If already in focus then the tree probably collapsed or expanded
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_EXPANDABLE):
-            if state.contains(pyatspi.STATE_EXPANDED):
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("expanded"))
-            else:
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("collapsed"))
-                
-        utterances.extend(self._getSpeechForObjectAvailability(obj))
-
-        self._debugGenerator("_getSpeechForListItem",
-                             obj,
-                             already_focused,
-                             utterances)
-        return utterances
-
-    def _getSpeechForMenu(self, obj, already_focused):
-        """Get the speech for a menu.
-
-        Arguments:
-        - obj: the menu
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self._getSpeechForAllTextSelection(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-            self._addSpeechForObjectAccelerator(obj, utterances)
-
-        self._debugGenerator("_getSpeechForMenu",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForMenuBar(self, obj, already_focused):
-        """Get the speech for a menu bar.
-
-        Arguments:
-        - obj: the menu bar
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-        self._debugGenerator("_getSpeechForMenuBar",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForMenuItem(self, obj, already_focused):
-        """Get the speech for a menu item.
-
-        Arguments:
-        - obj: the menu item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        # No need to say "menu item" because we already know that.
-        #
-        label = self._getSpeechForObjectLabel(obj)
-        utterances.extend(label)
-        name = self._getSpeechForObjectName(obj)
-        if name != label:
-            utterances.extend(name)
-
-        # OpenOffice check menu items currently have a role of "menu item"
-        # rather then "check menu item", so we need to test if one of the
-        # states is CHECKED. If it is, then add that in to the list of
-        # speech utterances. Note that we can't tell if this is a "check
-        # menu item" that is currently unchecked and speak that state. 
-        # See Orca bug #433398 for more details.
-        #
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this represents the state of a checked menu item.
-            #
-            utterances.append(_("checked"))
-
-        if not already_focused:
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-            self._addSpeechForObjectAccelerator(obj, utterances)
-
-        self._debugGenerator("_getSpeechForMenuItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForText(self, obj, already_focused):
-        """Get the speech for a text component.
-
-        Arguments:
-        - obj: the text component
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: WDW - HACK to remove availability because some text
-        # areas, such as those in yelp, come up as insensitive though
-        # they really are ineditable.]]]
-        #
-        utterances = []
-        utterances.extend(self._getSpeechForObjectLabel(obj))
-        if len(utterances) == 0:
-            if obj.name and (len(obj.name)):
-                utterances.append(obj.name)
-
-        if settings.presentReadOnlyText \
-           and self._script.isReadOnlyTextArea(obj):
-            utterances.append(settings.speechReadOnlyString)
-
-        if obj.getRole() != pyatspi.ROLE_PARAGRAPH:
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
-        utterances.append(text)
-
-        utterances.extend(self._getSpeechForAllTextSelection(obj))
-
-        self._addSpeechForObjectMnemonic(obj, utterances)
-
-        self._debugGenerator("_getSpeechForText",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForOptionPane(self, obj, already_focused):
-        """Get the speech for an option pane.
-
-        Arguments:
-        - obj: the option pane
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForOptionPane",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForPageTab(self, obj, already_focused):
-        """Get the speech for a page tab.
-
-        Arguments:
-        - obj: the page tab
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForPageTab",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForPageTabList(self, obj, already_focused):
-        """Get the speech for a page tab list.
-
-        Arguments:
-        - obj: the page tab list
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        #if obj.childCount == 1:
-        #    utterances.append(_("one tab"))
-        #else:
-        #    utterances.append(("%d " % obj.childCount) + _("tabs"))
-
-        self._debugGenerator("_getSpeechForPageTabList",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForProgressBar(self, obj, already_focused):
-        """Get the speech for a progress bar.  If the object already
-        had focus, just the new value is spoken.
-
-        Arguments:
-        - obj: the progress bar
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        value = obj.queryValue()
-        percentValue = (value.currentValue / \
-            (value.maximumValue - value.minimumValue)) * 100.0
-
-        # Translators: this is the percentage value of a progress bar.
-        #
-        percentage = _("%d percent.") % percentValue + " "
-
-        utterances = []
-
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self.getSpeechForObjectRole(obj))
-
-        utterances.append(percentage)
-
-        self._debugGenerator("_getSpeechForProgressBar",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForPushButton(self, obj, already_focused):
-        """Get the speech for a push button
-
-        Arguments:
-        - obj: the push button
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForPushButton",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForRadioButton(self, obj, already_focused):
-        """Get the speech for a radio button.  If the button already had
-        focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the check box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_CHECKED):
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            selectionState = C_("radiobutton", "selected")
-        else:
-            # Translators: this is in reference to a radio button being
-            # selected or not.
-            #
-            selectionState = C_("radiobutton", "not selected")
-
-        # If it's not already focused, say it's name
-        #
-        if not already_focused:
-            # The label is handled as a context in default.py
-            #
-            #utterances.extend(self._getSpeechForObjectLabel(obj))
-            utterances.extend(self._getSpeechForObjectName(obj))
-            utterances.append(selectionState)
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-        else:
-            utterances.append(selectionState)
-
-        self._debugGenerator("_getSpeechForRadioButton",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForRadioMenuItem(self, obj, already_focused):
-        """Get the speech for a radio menu item.  If the menu item
-        already had focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the radio menu item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-        utterances.extend(self._getSpeechForRadioButton(obj, False))
-
-        if not already_focused:
-            self._addSpeechForObjectAccelerator(obj, utterances)
-
-        self._debugGenerator("_getSpeechForRadioMenuItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForRowHeader(self, obj, already_focused):
-        """Get the speech for a row header.
-
-        Arguments:
-        - obj: the column header
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForRowHeader",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForScrollBar(self, obj, already_focused):
-        """Get the speech for a scroll bar.
-
-        Arguments:
-        - obj: the scroll bar
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        # [[[TODO: WDW - want to get orientation and maybe the
-        # percentage scrolled so far. Logged as bugzilla bug
-        # 319744.]]]
-        #
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForScrollBar",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForSlider(self, obj, already_focused):
-        """Get the speech for a slider.  If the object already
-        had focus, just the value is spoken.
-
-        Arguments:
-        - obj: the slider
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        valueString = self._script.getTextForValue(obj)
-
-        if already_focused:
-            utterances = [valueString]
-        else:
-            utterances = []
-            utterances.extend(self._getSpeechForObjectLabel(obj))
-            # Ignore the text on the slider.  See bug 340559
-            # (http://bugzilla.gnome.org/show_bug.cgi?id=340559): the
-            # implementors of the slider support decided to put in a
-            # Unicode left-to-right character as part of the text,
-            # even though that is not painted on the screen.
-            #
-            # In Java, however, there are sliders without a label. In
-            # this case, we'll add to presentation the slider name if
-            # it exists and we haven't found anything yet.
-            #
-            if not utterances:
-                utterances.extend(self._getSpeechForObjectName(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(valueString)
-            utterances.extend(self._getSpeechForRequiredObject(obj))
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-        self._debugGenerator("_getSpeechForSlider",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForSpinButton(self, obj, already_focused):
-        """Get the speech for a spin button.  If the object already has
-        focus, then only the new value is spoken.
-
-        Arguments:
-        - obj: the spin button
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        if already_focused:
-            utterances = [self._script.getDisplayedText(obj)]
-        else:
-            utterances = self._getDefaultSpeech(obj, already_focused)
-            utterances.extend(self._getSpeechForRequiredObject(obj))
-
-        self._debugGenerator("_getSpeechForSpinButton",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForSplitPane(self, obj, already_focused):
-        """Get the speech for a split pane.
-
-        Arguments:
-        - obj: the split pane
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        valueString = self._script.getTextForValue(obj)
-
-        if already_focused:
-            utterances = [valueString]
-        else:
-            utterances = []
-            utterances.extend(self._getSpeechForObjectLabel(obj))
-            if not utterances:
-                utterances.extend(self._getSpeechForObjectName(obj))
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(valueString)
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-
-        self._debugGenerator("_getSpeechForSplitPane",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTable(self, obj, already_focused):
-        """Get the speech for a table
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTable",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        # If this is a table with no children, then let the user know.
-        #
-        if not obj.childCount:
-            # Translators: this is the number of items in a layered pane
-            # or table.
-            #
-            utterances.append(_("0 items"))
-
-        return utterances
-
-    def _getSpeechForTableCell(self, obj, already_focused):
-        """Get the speech utterances for a single table cell
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        # If this table cell has 2 children and one of them has a 
-        # 'toggle' action and the other does not, then present this 
-        # as a checkbox where:
-        # 1) we get the checked state from the cell with the 'toggle' action
-        # 2) we get the label from the other cell.
-        # See Orca bug #376015 for more details.
-        #
-        if obj.childCount == 2:
-            cellOrder = []
-            hasToggle = [ False, False ]
-            for i, child in enumerate(obj):
-                try:
-                    action = child.queryAction()
-                except NotImplementedError:
-                    continue
-                else:
-                    for j in range(0, action.nActions):
-                        # Translators: this is the action name for
-                        # the 'toggle' action. It must be the same
-                        # string used in the *.po file for gail.
-                        #
-                        if action.getName(j) in ["toggle", _("toggle")]:
-                            hasToggle[i] = True
-                            break
-
-            if hasToggle[0] and not hasToggle[1]:
-                cellOrder = [ 1, 0 ] 
-            elif not hasToggle[0] and hasToggle[1]:
-                cellOrder = [ 0, 1 ]
-            if cellOrder:
-                for i in cellOrder:
-                    # Don't speak the label if just the checkbox state has
-                    # changed.
-                    #
-                    if already_focused and not hasToggle[i]:
-                        pass
-                    else:
-                        utterances.extend( \
-                            self._getSpeechForTableCell(obj[i],
-                                                        already_focused))
-                return utterances
-
-        # [[[TODO: WDW - Attempt to infer the cell type.  There's a
-        # bunch of stuff we can do here, such as check the EXPANDABLE
-        # state, check the NODE_CHILD_OF relation, etc.  Logged as
-        # bugzilla bug 319750.]]]
-        #
-        try:
-            action = obj.queryAction()
-        except NotImplementedError:
-            action = None
-        if action:
-            for i in range(0, action.nActions):
-                debug.println(debug.LEVEL_FINEST,
-                    "speechgenerator.__getTableCellUtterances " \
-                    + "looking at action %d" % i)
-
-                # Translators: this is the action name for
-                # the 'toggle' action. It must be the same
-                # string used in the *.po file for gail.
-                #
-                if action.getName(i) in ["toggle", _("toggle")]:
-                    utterances = self._getSpeechForCheckBox(obj,
-                                                            already_focused)
-                    break
-
-        displayedText = self._script.getDisplayedText( \
-                          self._script.getRealActiveDescendant(obj))
-        if not already_focused and not displayedText in utterances:
-            utterances.append(displayedText)
-
-        # If there is no displayed text, check to see if this table cell 
-        # contains an icon (image). If yes:
-        #   1/ Try to get a description for it and speak that.
-        #   2/ Treat the object of role type ROLE_IMAGE and speak
-        #      the role name.
-        # See bug #465989 for more details.
-        #
-        # [[TODO: eitani - incorprate this in new rolenames ]]
-        try:
-            image = obj.queryImage()
-        except:
-            image = None
-
-        if (not displayedText or len(displayedText) == 0) and image:
-            if not already_focused:
-                if image.imageDescription:
-                    utterances.append(image.imageDescription)
-                utterances.extend(self._getSpeechForImage(obj, already_focused))
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_EXPANDABLE):
-            if state.contains(pyatspi.STATE_EXPANDED):
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("expanded"))
-                childNodes = self._script.getChildNodes(obj)
-                children = len(childNodes)
-
-                if not children \
-                   or (settings.speechVerbosityLevel == \
-                       settings.VERBOSITY_LEVEL_VERBOSE):
-                    # Translators: this is the number of items in a layered
-                    # pane or table.
-                    #
-                    itemString = ngettext("%d item",
-                                          "%d items",
-                                          children) % children
-                    utterances.append(itemString)
-            else:
-                # Translators: this represents the state of a node in a tree.
-                # 'expanded' means the children are showing.
-                # 'collapsed' means the children are not showing.
-                #
-                utterances.append(_("collapsed"))
-
-        utterances.extend(self._getSpeechForRequiredObject(obj))
-
-        self._debugGenerator("_getSpeechForTableCell",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTableCellRow(self, obj, already_focused):
-        """Get the speech for a table cell row or a single table cell
-        if settings.readTableCellRow is False.
-
-        Arguments:
-        - obj: the table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        if (not already_focused):
-            try:
-                parent_table = obj.parent.queryTable()
-            except NotImplementedError:
-                parent_table = None
-            if settings.readTableCellRow and parent_table \
-                and (not self._script.isLayoutOnly(obj.parent)):
-                parent = obj.parent
-                index = self._script.getCellIndex(obj)
-                row = parent_table.getRowAtIndex(index)
-                column = parent_table.getColumnAtIndex(index)
-
-                # This is an indication of whether we should speak all the
-                # table cells (the user has moved focus up or down a row),
-                # or just the current one (focus has moved left or right in
-                # the same row).
-                #
-                speakAll = True
-                if "lastRow" in self._script.pointOfReference and \
-                    "lastColumn" in self._script.pointOfReference:
-                    pointOfReference = self._script.pointOfReference
-                    speakAll = (pointOfReference["lastRow"] != row) or \
-                        ((row == 0 or row == parent_table.nRows-1) and \
-                           pointOfReference["lastColumn"] == column)
-
-                if speakAll:
-                    for i in range(0, parent_table.nColumns):
-                        cell = parent_table.getAccessibleAt(row, i)
-                        if not cell:
-                            debug.println(debug.LEVEL_WARNING,
-                                 "ERROR: speechgenerator." \
-                                 + "_getSpeechForTableCellRow" \
-                                 + " no accessible at (%d, %d)" % (row, i))
-                            continue
-                        state = cell.getState()
-                        showing = state.contains(pyatspi.STATE_SHOWING)
-                        if showing:
-                            # If this table cell has a "toggle" action, and
-                            # doesn't have any label associated with it then 
-                            # also speak the table column header.
-                            # See Orca bug #455230 for more details.
-                            #
-                            label = self._script.getDisplayedText( \
-                                self._script.getRealActiveDescendant(cell))
-                            try:
-                                action = cell.queryAction()
-                            except NotImplementedError:
-                                action = None
-                            if action and (label == None or len(label) == 0):
-                                for j in range(0, action.nActions):
-                                    # Translators: this is the action name for
-                                    # the 'toggle' action. It must be the same
-                                    # string used in the *.po file for gail.
-                                    #
-                                    if action.getName(j) in ["toggle", \
-                                                             _("toggle")]:
-                                        accHeader = \
-                                            parent_table.getColumnHeader(i)
-                                        utterances.append(accHeader.name)
-
-                            utterances.extend(self._getSpeechForTableCell(cell,
-                                                           already_focused))
-                else:
-                    utterances.extend(self._getSpeechForTableCell(obj,
-                                                           already_focused))
-            else:
-                utterances = self._getSpeechForTableCell(obj, already_focused)
-        else:
-            utterances = self._getSpeechForTableCell(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTableCellRow",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTableColumnHeader(self, obj, already_focused):
-        """Get the speech for a table column header
-
-        Arguments:
-        - obj: the table column header
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getSpeechForColumnHeader(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTableColumnHeader",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTableRowHeader(self, obj, already_focused):
-        """Get the speech for a table row header
-
-        Arguments:
-        - obj: the table row header
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getSpeechForRowHeader(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTableRowHeader",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTearOffMenuItem(self, obj, already_focused):
-        """Get the speech for a tear off menu item
-
-        Arguments:
-        - obj: the tear off menu item
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE:
-            utterances = [rolenames.getSpeechForRoleName(obj)]
-        else:
-            # Translators: brief spoken words for the rolename of a tear off
-            # menu item.
-            #
-            utterances = [_("tear off")]
-
-        self._debugGenerator("_getSpeechForTearOffMenuItem",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTerminal(self, obj, already_focused):
-        """Get the speech for a terminal
-
-        Arguments:
-        - obj: the terminal
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        title = None
-        frame = self._script.getFrame(obj)
-        if frame:
-            title = frame.name
-        if not title:
-            title = self._script.getDisplayedLabel(obj)
-
-        utterances = [title]
-
-        self._debugGenerator("_getSpeechForTerminal",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForToggleButton(self, obj, already_focused):
-        """Get the speech for a toggle button.  If the toggle button already
-        had focus, then only the state is spoken.
-
-        Arguments:
-        - obj: the check box
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = []
-
-        state = obj.getState()
-        if state.contains(pyatspi.STATE_CHECKED) \
-           or state.contains(pyatspi.STATE_PRESSED):
-            # Translators: the state of a toggle button.
-            #
-            checkedState = _("pressed")
-        else:
-            # Translators: the state of a toggle button.
-            #
-            checkedState = _("not pressed")
-
-        # If it's not already focused, say it's name
-        #
-        if not already_focused:
-            label = self._getSpeechForObjectLabel(obj)
-            utterances.extend(label)
-            name = self._getSpeechForObjectName(obj)
-            if name != label:
-                utterances.extend(name)
-            utterances.extend(self.getSpeechForObjectRole(obj))
-            utterances.append(checkedState)
-            utterances.extend(self._getSpeechForObjectAvailability(obj))
-            self._addSpeechForObjectMnemonic(obj, utterances)
-        else:
-            utterances.append(checkedState)
-
-        self._debugGenerator("_getSpeechForToggleButton",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForToolBar(self, obj, already_focused):
-        """Get the speech for a tool bar
-
-        Arguments:
-        - obj: the tool bar
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForToolBar",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTree(self, obj, already_focused):
-        """Get the speech for a tree
-
-        Arguments:
-        - obj: the tree
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTree",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForTreeTable(self, obj, already_focused):
-        """Get the speech for a tree table
-
-        Arguments:
-        - obj: the tree table
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForTreeTable",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def _getSpeechForWindow(self, obj, already_focused):
-        """Get the speech for a window
-
-        Arguments:
-        - obj: the window
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken for the object.
-        """
-
-        utterances = self._getDefaultSpeech(obj, already_focused)
-
-        self._debugGenerator("_getSpeechForWindow",
-                             obj,
-                             already_focused,
-                             utterances)
-
-        return utterances
-
-    def getSpeech(self, obj, already_focused):
-        """Get the speech for an Accessible object.  This will look
-        first to the specific speech generators and then to the
-        default speech generator.  This method is the primary method
-        that external callers of this class should use.
-
-        Arguments:
-        - obj: the object
-        - already_focused: False if object just received focus
-
-        Returns a list of utterances to be spoken.
-        """
-        role = obj.getRole()
-        if role in self.speechGenerators:
-            generator = self.speechGenerators[role]
-        else:
-            generator = self._getDefaultSpeech
-
-        return [" ".join(generator(obj, already_focused))]
-
-    def getSpeechContext(self, obj, stopAncestor=None):
-        """Get the speech that describes the names and role of
-        the container hierarchy of the object, stopping at and
-        not including the stopAncestor.
-
-        Arguments:
-        - obj: the object
-        - stopAncestor: the anscestor to stop at and not include (None
-          means include all ancestors)
-
-        Returns a list of utterances to be spoken.
-        """
-
-        utterances = []
-
-        if not obj:
-            return utterances
-
-        if obj == stopAncestor:
-            return utterances
-
-        parent = obj.parent
-        if parent \
-            and (obj.getRole() == pyatspi.ROLE_TABLE_CELL) \
-            and (parent.getRole() == pyatspi.ROLE_TABLE_CELL):
-            parent = parent.parent
-
-        while parent and (parent.parent != parent):
-            if parent == stopAncestor:
-                break
-            if not self._script.isLayoutOnly(parent):
-                text = self._script.getDisplayedLabel(parent)
-                if not text and 'Text' in pyatspi.listInterfaces(parent):
-                    text = self._script.getDisplayedText(parent)
-                if text and len(text.strip()):
-                    # Push announcement of cell to the end
-                    #
-                    if parent.getRole() not in [pyatspi.ROLE_TABLE_CELL,
-                                                pyatspi.ROLE_FILLER]:
-                        utterances.extend(self.getSpeechForObjectRole(parent))
-                    utterances.append(text)
-                    if parent.getRole() == pyatspi.ROLE_TABLE_CELL:
-                        utterances.extend(self.getSpeechForObjectRole(parent))
-
-            parent = parent.parent
-
-        utterances.reverse()
-
-        return utterances
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index 133ac0f..aa7c0cd 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -1765,30 +1765,18 @@ class StructuralNavigation:
         """
 
         self._script.updateBraille(obj)
-        utterances = []
-        strings = self._script.speechGenerator.getSpeech(obj, False)
-        for string in strings:
-            voice = self._getVoice(obj, string)
-            speech.speak(string, voice)
-
-    def _getVoice(self, obj, string):
-        """Returns the voice to speak anything for the given obj.
-
-        Arguments:
-        - obj: the accessible object to be presented.
-        - string: the string to be spoken for obj.
-        """
 
+        # [[[TODO: WDW - move the voice selection to formatting.py
+        # at some point.]]]
+        #
         voices = self._script.voices
-
         if obj.getRole() == pyatspi.ROLE_LINK:
             voice = voices[settings.HYPERLINK_VOICE]
-        elif string and string.isupper() and string.strip().isalpha():
-            voice = voices[settings.UPPERCASE_VOICE]
         else:
-            voice = voices[settings.DEFAULT_VOICE]
+            voice = None
 
-        return voice
+        utterances = self._script.speechGenerator.getSpeech(obj)
+        speech.speak(utterances, voice)
 
     #########################################################################
     #                                                                       #
diff --git a/src/orca/where_am_I.py b/src/orca/where_am_I.py
index cacb82e..835f6a2 100644
--- a/src/orca/where_am_I.py
+++ b/src/orca/where_am_I.py
@@ -1,6 +1,6 @@
 # Orca
 #
-# Copyright 2005-2008 Sun Microsystems Inc.
+# Copyright 2005-2009 Sun Microsystems Inc.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -22,7 +22,7 @@
 __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
-__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
 __license__   = "LGPL"
 
 import pyatspi
@@ -136,7 +136,7 @@ class WhereAmI:
 
         elif role == pyatspi.ROLE_ICON:
             self._speakIconPanel(obj, basicOnly)
-            
+
         elif role == pyatspi.ROLE_LINK:
             self._speakLink(obj, basicOnly)
 
@@ -190,7 +190,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "check box utterances=%s" \
                       % utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakRadioButton(self, obj, basicOnly):
         """Radio Buttons present the following information (an example is
@@ -242,7 +242,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "radio button utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakComboBox(self, obj, basicOnly):
         """Comboboxes present the following information (an example is
@@ -278,7 +278,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "combo box utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakSpinButton(self, obj, basicOnly):
         """Spin Buttons present the following information (an example is
@@ -302,7 +302,7 @@ class WhereAmI:
         name = self._getObjName(obj)
         if name != label:
             utterances.append(name)
-        
+
         utterances.extend(self._getSpeechForAllTextSelection(obj))
 
         text = self._getObjAccelerator(obj)
@@ -317,7 +317,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "spin button utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakPushButton(self, obj, basicOnly):
         """ Push Buttons present the following information (an example is
@@ -344,7 +344,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "push button utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakSlider(self, obj, basicOnly):
         """Sliders present the following information (examples include
@@ -383,7 +383,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "slider utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakMenuItem(self, obj, basicOnly):
         """Menu items present the following information (examples include
@@ -399,8 +399,8 @@ class WhereAmI:
         """
 
         utterances = []
-        text = self.getObjLabelAndName(obj.parent) + " " + \
-               self._getSpeechForRoleName(obj.parent)
+        text = self.getObjLabelAndName(obj.parent) + " " \
+               + self._getSpeechForRoleName(obj.parent, force=True)
         utterances.append(text.strip())
 
         text = self.getObjLabelAndName(obj)
@@ -448,7 +448,7 @@ class WhereAmI:
         utterances.append(text)
 
         if obj.parent \
-           and obj.parent.getRole() in [pyatspi.ROLE_MENU, 
+           and obj.parent.getRole() in [pyatspi.ROLE_MENU,
                                         pyatspi.ROLE_MENU_BAR]:
             text = self._getObjMnemonic(obj)
             utterances.append(text)
@@ -458,7 +458,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "menu item utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakPageTab(self, obj, basicOnly):
         """Tabs in a Tab List present the following information (an example
@@ -492,7 +492,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "page utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakText(self, obj, basicOnly):
         """Text boxes present the following information (an example is
@@ -556,7 +556,7 @@ class WhereAmI:
         debug.println(self._debugLevel, "first text utterances=%s" % \
                       utterances)
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
         if not basicOnly:
             settings.verbalizePunctuationStyle = savedStyle
@@ -577,7 +577,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "text utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakTableCell(self, obj, basicOnly):
         """Tree Tables present the following information (an example is
@@ -639,7 +639,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "first table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
         utterances = []
         if table:
@@ -652,7 +652,7 @@ class WhereAmI:
             #
             text = _("row %d of %d") % ((row + 1), table.nRows)
             utterances.append(text)
-            speech.speakUtterances(utterances)
+            speech.speak(utterances)
 
             # Speak the current row if performing a "detailed" whereAmI.
             #
@@ -661,8 +661,8 @@ class WhereAmI:
                 debug.println(self._debugLevel, \
                               "second table cell utterances=%s" % \
                               utterances)
-                speech.speakUtterances(utterances)
-        
+                speech.speak(utterances)
+
         utterances = []
         state = obj.getState()
         if state.contains(pyatspi.STATE_EXPANDABLE):
@@ -692,7 +692,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "third table cell utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakListItem(self, obj, basicOnly):
         """List items should be treated like tree cells:
@@ -712,7 +712,7 @@ class WhereAmI:
         if text:
             utterances.append(text)
 
-        text = self._getSpeechForRoleName(obj)
+        text = self._getSpeechForRoleName(obj, force=True)
         utterances.append(text)
 
         text = self._getObjName(obj)
@@ -770,7 +770,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "list item utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakParagraph(self, obj, basicOnly):
         """Speak a paragraph object.
@@ -804,10 +804,10 @@ class WhereAmI:
         [frame, dialogue] = self._getFrameAndDialog(obj)
         utterances.extend(getTutorial(frame, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
-        
+        speech.speak(utterances)
+
     def _speakLink(self, obj, basicOnly):
-        """Speaks information about a link including protocol, domain 
+        """Speaks information about a link including protocol, domain
         comparisons and size of file if possible.
         Also tutorial string if enableTutorialMessages is set.
 
@@ -815,9 +815,9 @@ class WhereAmI:
         - obj: the icon object that currently has focus.
         - basicOnly: True if the user is performing a standard/basic whereAmI.
         """
-        
+
         # get the URI for the link of interest and parse it.
-        # parsed URI is returned as a tuple containing six components: 
+        # parsed URI is returned as a tuple containing six components:
         # scheme://netloc/path;parameters?query#fragment.
         link_uri = self._script.getURI(obj)
         if link_uri:
@@ -826,15 +826,15 @@ class WhereAmI:
             # It might be an anchor.  Try to speak the text.
             #
             return self._speakText(obj, basicOnly)
-      
+
         # Try to get the URI of the active document and parse it
         doc_uri = self._script.getDocumentFrameURI()
         if doc_uri:
             doc_uri_info = urlparse.urlparse(doc_uri)
         else:
             doc_uri_info = None
-              
-        # initialize our three outputs.  Output may change below for some 
+
+        # initialize our three outputs.  Output may change below for some
         # protocols.
         # Translators: this is the protocol of a link eg. http, mailto.
         #
@@ -858,7 +858,7 @@ class WhereAmI:
 
         domainoutput = ''
         sizeoutput = ''
-      
+
         # get size and other protocol specific information
         if link_uri_info[0] == 'ftp' or \
            link_uri_info[0] == 'ftps' or \
@@ -868,7 +868,7 @@ class WhereAmI:
             linkoutput = _('%s link to %s') %(link_uri_info[0], filename[-1])
             sizestr = self.__extractSize(link_uri)
             sizeoutput = self.__formatSizeOutput(sizestr)
-   
+
         # determine location differences if doc uri info is available
         if doc_uri_info:
             if link_uri_info[1] == doc_uri_info[1]:
@@ -885,7 +885,7 @@ class WhereAmI:
                 if len(linkdomain) > 1 and docdomain > 1  \
                     and linkdomain[-1] == docdomain[-1]  \
                     and linkdomain[-2] == docdomain[-2]:
-                    domainoutput = _('same site') 
+                    domainoutput = _('same site')
                 else:
                     domainoutput = _('different site')
 
@@ -893,7 +893,7 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakToggleButton(self, obj, basicOnly):
         """Speak toggle button information:
@@ -923,8 +923,8 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
-      
+        speech.speak(utterances)
+
     def _speakSplitPane(self, obj, basicOnly):
         """Speak split pane information:
            1. Name/Label
@@ -946,7 +946,7 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakLabel(self, obj, basicOnly):
         """Speak label information:
@@ -968,7 +968,7 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
 
     def _speakLayeredPane(self, obj, basicOnly):
@@ -990,7 +990,7 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
 
     def _getSpeechForAllTextSelection(self, obj):
@@ -1022,7 +1022,7 @@ class WhereAmI:
     def _getSelectedItemCount(self, obj, basicOnly):
         """Return an utterance indicating how many items are selected in this
         object, the current item, and (if a detailed whereAmI), the names of
-        all the selected items. This object will be an icon panel or a 
+        all the selected items. This object will be an icon panel or a
         layered pane.
 
         Arguments:
@@ -1077,7 +1077,7 @@ class WhereAmI:
                 return None
         except (ValueError, urllib2.URLError, OSError):
             return None
-  
+
     def __formatSizeOutput(self, sizestr):
         """Format the size output announcement.  Changes wording based on
         size.
@@ -1097,7 +1097,7 @@ class WhereAmI:
         elif size >= 1000000:
             # Translators: This is the size of a file in megabytes
             #
-            return _('%.2f megabytes') % (float(size) * .000001) 
+            return _('%.2f megabytes') % (float(size) * .000001)
 
     def _speakGenericObject(self, obj, basicOnly):
         """Speak a generic object; one not specifically handled by
@@ -1114,7 +1114,7 @@ class WhereAmI:
         getTutorial = self._script.tutorialGenerator.getTutorial
         utterances.extend(getTutorial(obj, False, forceMessage=True))
 
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
 
     def _getObjName(self, obj):
@@ -1171,15 +1171,23 @@ class WhereAmI:
 
         return text.strip()
 
-    def _getSpeechForRoleName(self, obj, role=None):
+    # pylint: disable-msg=W0142
+
+    def _getSpeechForRoleName(self, obj, **args):
         """Returns the rolename to be spoken for the object.
         """
 
         try:
-            return self._script.speechGenerator.\
-                getSpeechForObjectRole(obj, role)[0]
+            result = self._script.speechGenerator.getRoleName(obj, **args)
+            if result:
+                result = result[0]
+            else:
+                result = ""
         except:
-            return ""
+            debug.printException(debug.LEVEL_WARNING)
+            result = ""
+
+        return result
 
     def _getGroupLabel(self, obj):
         """Returns the label for a group of components.
@@ -1279,7 +1287,7 @@ class WhereAmI:
         return text
 
     def _getObjAccelerator(self,
-                           obj, 
+                           obj,
                            fallbackToMnemonic=True,
                            fallbackToFullPath=True):
         """Returns the accelerator for the object, if it exists.
@@ -1379,7 +1387,7 @@ class WhereAmI:
                     break
 
         if isToggle:
-            text = self._getSpeechForRoleName(obj, pyatspi.ROLE_CHECK_BOX)
+            text = self._getSpeechForRoleName(obj, role=pyatspi.ROLE_CHECK_BOX)
             text = text + " " + self._getCheckBoxState(obj)
         else:
             descendant = self._script.getRealActiveDescendant(obj)
@@ -1432,7 +1440,7 @@ class WhereAmI:
         Arguments:
         - obj: the text object to extract the selected text from.
 
-        Returns: the selected text contents plus the start and end 
+        Returns: the selected text contents plus the start and end
         offsets within the text.
         """
 
@@ -1816,14 +1824,14 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "titlebar utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def speakStatusBar(self, obj):
         """Speak the contents of the status bar of the window with focus.
         """
- 
+
         utterances = []
- 
+
         results = self._getFrameAndDialog(obj)
 
         if results[0]:
@@ -1837,7 +1845,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "status bar utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _getFrameAndDialog(self, obj):
         """Returns the frame and (possibly) the dialog containing
@@ -1903,7 +1911,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "statusbar utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _getDefaultButton(self, obj):
         """Gets the default button in a dialog.
@@ -1957,7 +1965,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "default button utterances=%s" % \
                       utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _speakObjDescription(self, obj):
         """Speaks the object's description if it is not the same as
@@ -1995,7 +2003,7 @@ class WhereAmI:
 
         debug.println(self._debugLevel, "toolbar utterances=%s" \
                       % utterances)
-        speech.speakUtterances(utterances)
+        speech.speak(utterances)
 
     def _getRequiredState(self, obj):
         """Returns a string describing the required state of the given
diff --git a/test/harness/.gitignore b/test/harness/.gitignore
new file mode 100644
index 0000000..21d9e04
--- /dev/null
+++ b/test/harness/.gitignore
@@ -0,0 +1,5 @@
+orca-customizations.py
+orca-customizations.pyc
+user-settings.py
+user-settings.pyc
+utils.pyc
diff --git a/test/harness/runone.sh b/test/harness/runone.sh
index 80a526d..ba7bd87 100755
--- a/test/harness/runone.sh
+++ b/test/harness/runone.sh
@@ -86,7 +86,7 @@ then
     source $PARAMS_FILE
 fi
 
-# Run the app (or gnome-terminal if no app was given) and let it settle in.
+# Run the app (or gtk-demo if no app was given) and let it settle in.
 #
 ARGS=""
 if [ -n "$3" ]
@@ -94,7 +94,7 @@ then
     APP_NAME=$2
     orcaRunning=$3
 else
-   APP_NAME=gnome-terminal
+   APP_NAME=gtk-demo
    if [ -n "$2" ]
    then
        orcaRunning=$2
diff --git a/test/keystrokes/firefox/bug_511389.py b/test/keystrokes/firefox/bug_511389.py
index ce68752..8bbf837 100644
--- a/test/keystrokes/firefox/bug_511389.py
+++ b/test/keystrokes/firefox/bug_511389.py
@@ -56,7 +56,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab",
     ["BRAILLE LINE:  'Bar'",
      "     VISIBLE:  'Bar', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bar link'"]))
 
 ########################################################################
@@ -69,7 +68,6 @@ sequence.append(utils.AssertPresentationAction(
     "Shift Tab",
     ["BRAILLE LINE:  'Foo'",
      "     VISIBLE:  'Foo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Foo link'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/bug_544771.py b/test/keystrokes/firefox/bug_544771.py
index db18a1e..070633f 100644
--- a/test/keystrokes/firefox/bug_544771.py
+++ b/test/keystrokes/firefox/bug_544771.py
@@ -50,7 +50,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Tab", 
     ["BRAILLE LINE:  'â?¢ First item'",
      "     VISIBLE:  'â?¢ First item', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'First item link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -59,7 +58,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Tab", 
     ["BRAILLE LINE:  'â?¢ Second item'",
      "     VISIBLE:  'â?¢ Second item', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Second item link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -68,7 +66,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Return", 
     ["BRAILLE LINE:  ''",
      "     VISIBLE:  '', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'link'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/bug_552887a.py b/test/keystrokes/firefox/bug_552887a.py
index 106b755..3cd26c8 100644
--- a/test/keystrokes/firefox/bug_552887a.py
+++ b/test/keystrokes/firefox/bug_552887a.py
@@ -244,7 +244,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  ''",
      "     VISIBLE:  '', cursor=0",
      "SPEECH OUTPUT: '",
-     " link'"]))
+     " link image'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/bug_568631.py b/test/keystrokes/firefox/bug_568631.py
index ff95d87..a37e4af 100644
--- a/test/keystrokes/firefox/bug_568631.py
+++ b/test/keystrokes/firefox/bug_568631.py
@@ -36,8 +36,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
     "Top of file", 
-    ["BRAILLE LINE:  'Home News Projects Art Support Development Community'",
-     "     VISIBLE:  'Home News Projects Art Support D', cursor=1",
+    ["BRAILLE LINE:  'Home News Projects Art Support Development Community'",
+     "     VISIBLE:  'Home News Projects Art Support D', cursor=1",
      "SPEECH OUTPUT: 'Home link News link Projects link Art link Support link Development link Community link'"]))
 
 ########################################################################
@@ -64,9 +64,8 @@ sequence.append(KeyComboAction("Return"))
 sequence.append(PauseAction(1000))
 sequence.append(utils.AssertPresentationAction(
     "Return",
-    ["BRAILLE LINE:  'About h1'",
+    ["BRAILLE LINE:  'About h1'",
      "     VISIBLE:  'About h1', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'About heading level 1'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/codetalks_alert.py b/test/keystrokes/firefox/codetalks_alert.py
index a38f58e..69c26d4 100644
--- a/test/keystrokes/firefox/codetalks_alert.py
+++ b/test/keystrokes/firefox/codetalks_alert.py
@@ -60,7 +60,6 @@ sequence.append(utils.AssertPresentationAction(
     "Press button", 
     ["BRAILLE LINE:  'close'",
      "     VISIBLE:  'close', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'close link'",
      "SPEECH OUTPUT: 'This popup is created as a div in the HTML content, rather than being created in the DOM at the time of use. The display style is changed from \"none\" to \"block\" to hide and show it. close '"]))
 
diff --git a/test/keystrokes/firefox/codetalks_button.py b/test/keystrokes/firefox/codetalks_button.py
index 0f3d857..bad17ca 100644
--- a/test/keystrokes/firefox/codetalks_button.py
+++ b/test/keystrokes/firefox/codetalks_button.py
@@ -40,8 +40,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Tracking number text entry", 
     ["BRAILLE LINE:  'Tracking number Tracking number  $l'",
      "     VISIBLE:  'Tracking number  $l', cursor=17",
-     "SPEECH OUTPUT: 'Order tracking panel'",
-     "SPEECH OUTPUT: 'Tracking number text '"]))
+     "SPEECH OUTPUT: 'Order tracking panel Tracking number text '"]))
 
 ########################################################################
 # Tab to the "Check Now" push button
@@ -53,7 +52,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Check Now push button",
     ["BRAILLE LINE:  'Check Now Button Check to see if your order has been shipped.  $l'",
      "     VISIBLE:  'Check Now Button Check to see if', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Check Now button'"]))
 
 ########################################################################
@@ -67,9 +65,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereamI", 
     ["BRAILLE LINE:  'Check Now Button Check to see if your order has been shipped.  $l'",
      "     VISIBLE:  'Check Now Button Check to see if', cursor=1",
-     "SPEECH OUTPUT: 'Check Now'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'Check Now button '",
      "SPEECH OUTPUT: 'Check to see if your order has been shipped.'"]))
 
 ########################################################################
@@ -85,7 +81,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application The page at http://codetalks.org says: Dialog OK Button'",
      "     VISIBLE:  'OK Button', cursor=1",
      "SPEECH OUTPUT: 'The page at http://codetalks.org says: Button pressed'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'OK button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/codetalks_tree.py b/test/keystrokes/firefox/codetalks_tree.py
index f3751e6..8e39b71 100644
--- a/test/keystrokes/firefox/codetalks_tree.py
+++ b/test/keystrokes/firefox/codetalks_tree.py
@@ -39,11 +39,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  ' Fruits', cursor=1",
      "BRAILLE LINE:  ' Fruits'",
      "     VISIBLE:  ' Fruits', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Foods tree'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Fruits expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits expanded tree level 1'"]))
 
 ########################################################################
 # Left Arrow to collapse fruits.
@@ -68,12 +65,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  ' Fruits'",
      "     VISIBLE:  ' Fruits', cursor=1",
-     "SPEECH OUTPUT: 'Fruits'",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Fruits'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits list item Fruits item 1 of 2 collapsed tree level 1'"]))
 
 ########################################################################
 # Right Arrow to expand fruits.
@@ -98,12 +90,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  ' Fruits'",
      "     VISIBLE:  ' Fruits', cursor=1",
-     "SPEECH OUTPUT: 'Fruits'",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Fruits'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits list item Fruits item 1 of 2 expanded tree level 1'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/codetalks_treegrid.py b/test/keystrokes/firefox/codetalks_treegrid.py
index dfc0050..6b51b93 100644
--- a/test/keystrokes/firefox/codetalks_treegrid.py
+++ b/test/keystrokes/firefox/codetalks_treegrid.py
@@ -34,10 +34,9 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Selectable Grid with Text with 9', cursor=1",
      "BRAILLE LINE:  '+A Question of Love'",
      "     VISIBLE:  '+A Question of Love', cursor=0",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Selectable Grid with Text with 9 Rows tree table'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Title +A Question of Love'"]))
+     "SPEECH OUTPUT: 'Title tree table'",
+     "SPEECH OUTPUT: '+A Question of Love'"]))
 
 ########################################################################
 # Down Arrow to the next two items.
@@ -48,7 +47,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Down Arrow", 
     ["BRAILLE LINE:  'Title + Piece of Peace Cell'",
      "     VISIBLE:  'Title + Piece of Peace Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '+ Piece of Peace'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -57,7 +55,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Down Arrow", 
     ["BRAILLE LINE:  'Title + International Law Cell'",
      "     VISIBLE:  'Title + International Law Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '+ International Law'"]))
 
 ########################################################################
@@ -69,7 +66,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Up Arrow", 
     ["BRAILLE LINE:  'Title + Piece of Peace Cell'",
      "     VISIBLE:  'Title + Piece of Peace Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '+ Piece of Peace'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -78,8 +74,7 @@ sequence.append(utils.AssertPresentationAction(
     "2. Up Arrow", 
     ["BRAILLE LINE:  '+A Question of Love'",
      "     VISIBLE:  '+A Question of Love', cursor=0",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Title +A Question of Love'"]))
+     "SPEECH OUTPUT: '+A Question of Love'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  
@@ -91,8 +86,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  '+A Question of Love'",
      "     VISIBLE:  '+A Question of Love', cursor=0",
-     "SPEECH OUTPUT: 'Title +A Question of Love'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Title +A Question of Love '"]))
 
 ########################################################################
 # Space to expand the current item.
@@ -116,8 +110,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  '-A Question of Love'",
      "     VISIBLE:  '-A Question of Love', cursor=0",
-     "SPEECH OUTPUT: 'Title -A Question of Love'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Title -A Question of Love '"]))
 
 ########################################################################
 # Down Arrow to the child item.
@@ -128,7 +121,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow into child", 
     ["BRAILLE LINE:  'ISBN 978-3-453-40540-0 Cell Author Nora Roberts Cell Price $ 9.99 Cell'",
      "     VISIBLE:  'ISBN 978-3-453-40540-0 Cell Auth', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '978-3-453-40540-0'"]))
 
 ########################################################################
@@ -140,7 +132,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Right Arrow in child", 
     ["BRAILLE LINE:  'ISBN 978-3-453-40540-0 Cell Author Nora Roberts Cell Price $ 9.99 Cell'",
      "     VISIBLE:  'Author Nora Roberts Cell Price $', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Nora Roberts'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -149,7 +140,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Right Arrow in child", 
     ["BRAILLE LINE:  'ISBN 978-3-453-40540-0 Cell Author Nora Roberts Cell Price $ 9.99 Cell'",
      "     VISIBLE:  'Price $ 9.99 Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '$ 9.99'"]))
 
 ########################################################################
@@ -161,7 +151,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Left Arrow in child", 
     ["BRAILLE LINE:  'ISBN 978-3-453-40540-0 Cell Author Nora Roberts Cell Price $ 9.99 Cell'",
      "     VISIBLE:  'Author Nora Roberts Cell Price $', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Nora Roberts'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -170,7 +159,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Left Arrow in child", 
     ["BRAILLE LINE:  'ISBN 978-3-453-40540-0 Cell Author Nora Roberts Cell Price $ 9.99 Cell'",
      "     VISIBLE:  'ISBN 978-3-453-40540-0 Cell Auth', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '978-3-453-40540-0'"]))
 
 ########################################################################
@@ -182,8 +170,7 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow back to parent", 
     ["BRAILLE LINE:  '-A Question of Love'",
      "     VISIBLE:  '-A Question of Love', cursor=0",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Title -A Question of Love'"]))
+     "SPEECH OUTPUT: '-A Question of Love'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/dojo_button.py b/test/keystrokes/firefox/dojo_button.py
index 686a8ca..b24ea84 100644
--- a/test/keystrokes/firefox/dojo_button.py
+++ b/test/keystrokes/firefox/dojo_button.py
@@ -36,7 +36,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the <button> button", 
     ["BRAILLE LINE:  '<button> <input type='button'> Button       Create â?? Edit! â?? Color â?? Save â??   '",
      "     VISIBLE:  '<button> <input type='button'> B', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '<button> button'"]))
 
 ########################################################################
@@ -49,9 +48,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I on <button>", 
     ["BRAILLE LINE:  '<button> <input type='button'> Button       Create â?? Edit! â?? Color â?? Save â??   '",
      "     VISIBLE:  '<button> <input type='button'> B', cursor=1",
-     "SPEECH OUTPUT: '<button>'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: '<button> button '"]))
 
 ########################################################################
 # Tab to <input type='button'>  
@@ -63,7 +60,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to <input type='button'>",
     ["BRAILLE LINE:  '<button> <input type='button'> Button       Create â?? Edit! â?? Color â?? Save â??   '",
      "     VISIBLE:  '<input type='button'> Button    ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '<input type='button'> button'"]))
 
 ########################################################################
@@ -76,9 +72,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I on <input type='button'>", 
     ["BRAILLE LINE:  '<button> <input type='button'> Button       Create â?? Edit! â?? Color â?? Save â??   '",
      "     VISIBLE:  '<input type='button'> Button    ', cursor=1",
-     "SPEECH OUTPUT: '<input type='button'>'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: '<input type='button'> button '"]))
 
 ########################################################################
 # Tab to "Create"  
@@ -91,7 +85,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Create",
     ["BRAILLE LINE:  'Create Button'",
      "     VISIBLE:  'Create Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Create button'",
      "SPEECH OUTPUT: 'tooltip on button'"]))
 
@@ -105,9 +98,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I on Create", 
     ["BRAILLE LINE:  'Create Button'",
      "     VISIBLE:  'Create Button', cursor=1",
-     "SPEECH OUTPUT: 'Create'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Create button '"]))
 
 # WDW - Tabbing to the Create button pops up a tooltip.  Should we present
 # it automatically?
@@ -128,7 +119,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Missing space between Button and Create, also Menu and Save",
      "BRAILLE LINE:  '<button> Button <input type='button'> ButtonCreate Button â?? MenuSave Button â?? Menu'",
      "     VISIBLE:  'â?? MenuSave Button â?? Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?? menu'"]))
 
 ########################################################################
@@ -141,9 +131,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I on drop down menu on Create", 
     ["BRAILLE LINE:  '<button> Button <input type='button'> ButtonCreate Button â?? MenuSave Button â?? Menu'",
      "     VISIBLE:  'â?? MenuSave Button â?? Menu', cursor=1",
-     "SPEECH OUTPUT: 'â??'",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'â?? menu '"]))
 
 ########################################################################
 # Open the drop down menu.
@@ -158,9 +146,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Create blank', cursor=1",
      "BRAILLE LINE:  'Menu'",
      "     VISIBLE:  'Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Create blank'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'"]))
 
 ########################################################################
@@ -173,7 +159,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down to Create from template", 
     ["BRAILLE LINE:  'Create from template'",
      "     VISIBLE:  'Create from template', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Create from template'"]))
 
 ########################################################################
@@ -186,10 +171,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I on Create from template", 
     ["BRAILLE LINE:  'Create from template'",
      "     VISIBLE:  'Create from template', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Create from template'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Create from template '"]))
 
 ########################################################################
 # Close the menu and go to the Edit! button
@@ -204,7 +186,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Why does it say Edit! twice?",
      "BRAILLE LINE:  'Edit! Edit! Menu'",
      "     VISIBLE:  'Edit! Edit! Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Edit! menu'"]))
 
 ########################################################################
@@ -220,9 +201,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Cut', cursor=1",
      "BRAILLE LINE:  'Menu'",
      "     VISIBLE:  'Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Cut'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -232,7 +211,6 @@ sequence.append(utils.AssertPresentationAction(
     "Go to Copy", 
     ["BRAILLE LINE:  'Copy'",
      "     VISIBLE:  'Copy', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Copy'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -242,7 +220,6 @@ sequence.append(utils.AssertPresentationAction(
     "Go to Paste", 
     ["BRAILLE LINE:  'Paste'",
      "     VISIBLE:  'Paste', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Paste'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -252,7 +229,6 @@ sequence.append(utils.AssertPresentationAction(
     "Goto Submenu", 
     ["BRAILLE LINE:  'Submenu'",
      "     VISIBLE:  'Submenu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Submenu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -265,9 +241,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Menu', cursor=1",
      "BRAILLE LINE:  'Submenu Item One'",
      "     VISIBLE:  'Submenu Item One', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Submenu Item One'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -277,7 +251,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down to Submenu Item Two", 
     ["BRAILLE LINE:  'Submenu Item Two'",
      "     VISIBLE:  'Submenu Item Two', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Submenu Item Two'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -287,7 +260,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down to Deeper Submenu", 
     ["BRAILLE LINE:  'Deeper Submenu'",
      "     VISIBLE:  'Deeper Submenu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Deeper Submenu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -300,9 +272,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Menu', cursor=1",
      "BRAILLE LINE:  'Sub-sub-menu Item One'",
      "     VISIBLE:  'Sub-sub-menu Item One', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Sub-sub-menu Item One'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -312,7 +282,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down to Sub-sub-menu Item Two", 
     ["BRAILLE LINE:  'Sub-sub-menu Item Two'",
      "     VISIBLE:  'Sub-sub-menu Item Two', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Sub-sub-menu Item Two'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -324,9 +293,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Menu', cursor=1",
      "BRAILLE LINE:  'Deeper Submenu'",
      "     VISIBLE:  'Deeper Submenu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Deeper Submenu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -338,9 +305,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Menu Menu', cursor=6",
      "BRAILLE LINE:  'Submenu'",
      "     VISIBLE:  'Submenu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Submenu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -353,9 +318,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Menu', cursor=1",
      "BRAILLE LINE:  'Edit! Edit! Menu'",
      "     VISIBLE:  'Edit! Edit! Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Edit! menu'"]))
 
 ########################################################################
@@ -369,7 +332,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Why does it say Color twice?",
      "BRAILLE LINE:  'Color Color Menu'",
      "     VISIBLE:  'Color Color Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Color menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -380,9 +342,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - speaks 'not selected' apparently due to Down into a table cell",
      "BRAILLE LINE:  'white Image lime Image green Image blue Image'",
      "     VISIBLE:  'white Image lime Image green Ima', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'white'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'white not selected'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
@@ -391,7 +351,6 @@ sequence.append(utils.AssertPresentationAction(
     "Go to lime", 
     ["BRAILLE LINE:  'white Image lime Image green Image blue Image'",
      "     VISIBLE:  'lime Image green Image blue Imag', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'lime'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -401,7 +360,6 @@ sequence.append(utils.AssertPresentationAction(
     "Go to green", 
     ["BRAILLE LINE:  'white Image lime Image green Image blue Image'",
      "     VISIBLE:  'green Image blue Image', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'green'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -411,7 +369,6 @@ sequence.append(utils.AssertPresentationAction(
     "Go to blue", 
     ["BRAILLE LINE:  'white Image lime Image green Image blue Image'",
      "     VISIBLE:  'blue Image', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'blue'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -422,9 +379,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - speaks 'not selected' apparently due to Down into a table cell",
      "BRAILLE LINE:  'silver Image yellow Image fuchsia Image navy Image'",
      "     VISIBLE:  'navy Image', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'navy'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'navy not selected'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
@@ -433,7 +388,6 @@ sequence.append(utils.AssertPresentationAction(
     "Goto fuchsia", 
     ["BRAILLE LINE:  'silver Image yellow Image fuchsia Image navy Image'",
      "     VISIBLE:  'fuchsia Image navy Image', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'fuchsia'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -443,7 +397,6 @@ sequence.append(utils.AssertPresentationAction(
     "Goto yellow", 
     ["BRAILLE LINE:  'silver Image yellow Image fuchsia Image navy Image'",
      "     VISIBLE:  'yellow Image fuchsia Image navy ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'yellow'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -454,7 +407,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Why does it say Color twice?",
      "BRAILLE LINE:  'Color Color Menu'",
      "     VISIBLE:  'Color Color Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Color menu'"]))
 
 ########################################################################
@@ -472,7 +424,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the first unlabelled button ('+')", 
     ["BRAILLE LINE:  'Rich Text Test! Button'",
      "     VISIBLE:  'Rich Text Test! Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Rich Text Test! button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -482,7 +433,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the second unlabelled button ('Color')", 
     ["BRAILLE LINE:  'Color Menu'",
      "     VISIBLE:  'Color Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Color menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -492,7 +442,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the third unlabelled button ('Save')", 
     ["BRAILLE LINE:  'Save Button â?? Menu'",
      "     VISIBLE:  'Save Button â?? Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Save button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -502,7 +451,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the down arrow button", 
     ["BRAILLE LINE:  'Save Button â?? Menu'",
      "     VISIBLE:  'Save Button â?? Menu', cursor=13",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?? menu'"]))
 
 ########################################################################
@@ -515,7 +463,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the 'Toggle me' toggle button", 
     ["BRAILLE LINE:  '&=y Toggle me ToggleButton'",
      "     VISIBLE:  '&=y Toggle me ToggleButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Toggle me toggle button pressed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -545,7 +492,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the big button", 
     ["BRAILLE LINE:  'big Button'",
      "     VISIBLE:  'big Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'big button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -555,7 +501,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the small button", 
     ["BRAILLE LINE:  'small Button'",
      "     VISIBLE:  'small Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'small button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -565,7 +510,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the long button", 
     ["BRAILLE LINE:  'long Button'",
      "     VISIBLE:  'long Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'long button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -575,7 +519,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the tall button", 
     ["BRAILLE LINE:  'tall Button'",
      "     VISIBLE:  'tall Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'tall button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -585,7 +528,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the short button", 
     ["BRAILLE LINE:  'short Button'",
      "     VISIBLE:  'short Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'short button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -595,7 +537,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the bit longer button", 
     ["BRAILLE LINE:  'bit longer Button'",
      "     VISIBLE:  'bit longer Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'bit longer button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -605,7 +546,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the ridiculously long button", 
     ["BRAILLE LINE:  'ridiculously long Button'",
      "     VISIBLE:  'ridiculously long Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'ridiculously long button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/dojo_checkbox.py b/test/keystrokes/firefox/dojo_checkbox.py
index ba9b587..f7eb357 100644
--- a/test/keystrokes/firefox/dojo_checkbox.py
+++ b/test/keystrokes/firefox/dojo_checkbox.py
@@ -39,7 +39,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb0 checkbox", 
     ["BRAILLE LINE:  '< > CheckBox cb0: Vanilla (non-dojo) checkbox (for comparison purposes)'",
      "     VISIBLE:  '< > CheckBox cb0: Vanilla (non-d', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb0: Vanilla (non-dojo) checkbox (for comparison purposes) check box not checked'"]))
 
 ########################################################################
@@ -62,7 +61,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb1 checkbox", 
     ["BRAILLE LINE:  '< > CheckBox cb1: normal checkbox, with value=foo, clicking generates console log messages getValue()'",
      "     VISIBLE:  '< > CheckBox cb1: normal checkbo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb1: normal checkbox, with value=foo, clicking generates console log messages check box not checked'"]))
 
 ########################################################################
@@ -86,7 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb2 checkbox", 
     ["BRAILLE LINE:  '<x> CheckBox cb2: normal checkbox, with default value, initially turned on. \"onChange\" handler updates: [] getValue()'",
      "     VISIBLE:  '<x> CheckBox cb2: normal checkbo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb2: normal checkbox, with default value, initially turned on. check box checked'"]))
 
 ########################################################################
@@ -99,7 +96,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb5 checkbox", 
     ["BRAILLE LINE:  '< > CheckBox cb5: normal checkbox, with specified value=\"\", clicking generates console log messages getValue()'",
      "     VISIBLE:  '< > CheckBox cb5: normal checkbo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb5: normal checkbox, with specified value=\"\", clicking generates console log messages check box not checked'"]))
 
 ########################################################################
@@ -112,7 +108,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb6 checkbox", 
     ["BRAILLE LINE:  '<x> CheckBox cb6: instantiated from script'",
      "     VISIBLE:  '<x> CheckBox cb6: instantiated f', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb6: instantiated from script check box checked'"]))
 
 ########################################################################
@@ -124,7 +119,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the cb7 checkbox", 
     ["BRAILLE LINE:  '< > CheckBox cb7: normal checkbox. disable Button enable Button set value to \"fish\" Button Reset value+checked Button \"onChange\" handler updates: []'",
      "     VISIBLE:  '< > CheckBox cb7: normal checkbo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'cb7: normal checkbox. check box not checked'"]))
 
 ########################################################################
@@ -137,8 +131,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '< > CheckBox cb7: normal checkbox. disable Button enable Button set value to \"fish\" Button Reset value+checked Button \"onChange\" handler updates: []'",
      "     VISIBLE:  '< > CheckBox cb7: normal checkbo', cursor=1",
-     "SPEECH OUTPUT: 'cb7: normal checkbox. check box not checked'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'cb7: normal checkbox. check box not checked '"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/dojo_combo_box.py b/test/keystrokes/firefox/dojo_combo_box.py
index b3d63cc..929fea3 100644
--- a/test/keystrokes/firefox/dojo_combo_box.py
+++ b/test/keystrokes/firefox/dojo_combo_box.py
@@ -40,8 +40,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to the first combo box", 
     ["BRAILLE LINE:  'â?? US State test 1 California $l'",
      "     VISIBLE:  'â?? US State test 1 California $l', cursor=0",
-     "SPEECH OUTPUT: 'US State test 1 combo box'",
-     "SPEECH OUTPUT: 'US State test 1 text California selected'"]))
+     "SPEECH OUTPUT: 'US State test 1 combo box US State test 1 text California selected'"]))
 
 ########################################################################
 # Replace all the text (already selected) with a 'C'.  
@@ -70,7 +69,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'â?? US State test 1 C $l', cursor=0",
      "BRAILLE LINE:  'â?¢ California'",
      "     VISIBLE:  'â?¢ California', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?¢ California'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -79,7 +77,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Down Arrow", 
     ["BRAILLE LINE:  'â?¢ Colorado'",
      "     VISIBLE:  'â?¢ Colorado', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?¢ Colorado'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -88,7 +85,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Down Arrow", 
     ["BRAILLE LINE:  'â?¢ Connecticut'",
      "     VISIBLE:  'â?¢ Connecticut', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?¢ Connecticut'"]))
 
 # Note that not saying anything here is correct because we're already at
@@ -110,7 +106,6 @@ sequence.append(utils.AssertPresentationAction(
     "1. Up Arrow", 
     ["BRAILLE LINE:  'â?¢ Colorado'",
      "     VISIBLE:  'â?¢ Colorado', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?¢ Colorado'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -119,7 +114,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Up Arrow", 
     ["BRAILLE LINE:  'â?¢ California'",
      "     VISIBLE:  'â?¢ California', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'â?¢ California'"]))
 
 # Note that not saying anything here is correct because we're already at
@@ -141,9 +135,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I - Combo box expanded", 
     ["BRAILLE LINE:  'â?¢ California'",
      "     VISIBLE:  'â?¢ California', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'â?¢ California'",
-     "SPEECH OUTPUT: 'item 1 of 3'"]))
+     "SPEECH OUTPUT: 'list item â?¢ California item 1 of 3'"]))
 
 ########################################################################
 # Escape to collapse the combo box.
@@ -154,8 +146,7 @@ sequence.append(utils.AssertPresentationAction(
     "Escape", 
     ["BRAILLE LINE:  'â?? US State test 1 California $l'",
      "     VISIBLE:  'â?? US State test 1 California $l', cursor=0",
-     "SPEECH OUTPUT: 'US State test 1 combo box'",
-     "SPEECH OUTPUT: 'US State test 1 text California selected'"]))
+     "SPEECH OUTPUT: 'US State test 1 combo box US State test 1 text California selected'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  
@@ -167,11 +158,8 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I - Combo box collapsed back into an entry", 
     ["BRAILLE LINE:  'â?? US State test 1 California $l'",
      "     VISIBLE:  'â?? US State test 1 California $l', cursor=0",
-     "SPEECH OUTPUT: 'US State test 1'",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'alifornia'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'US State test 1 text alifornia'",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/dojo_dialog.py b/test/keystrokes/firefox/dojo_dialog.py
index fdc65a9..cb3bd45 100644
--- a/test/keystrokes/firefox/dojo_dialog.py
+++ b/test/keystrokes/firefox/dojo_dialog.py
@@ -38,7 +38,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to show dialog button", 
     ["BRAILLE LINE:  'Show Dialog Button Programatic Dialog \(3 second delay\) Button Show TabContainer Dialog Button Test slow loading HREF Dialog Button Show File Dialog Button'",
      "     VISIBLE:  'Show Dialog Button Programatic D', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show Dialog button'"]))
      
 ########################################################################
@@ -50,7 +49,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to programatic dialog button", 
     ["BRAILLE LINE:  'Show Dialog Button Programatic Dialog \(3 second delay\) Button Show TabContainer Dialog Button Test slow loading HREF Dialog Button Show File Dialog Button'",
      "     VISIBLE:  'Programatic Dialog \(3 second del', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Programatic Dialog \(3 second delay\) button'"]))
      
 ########################################################################
@@ -62,7 +60,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to tabcontainer dialog button", 
     ["BRAILLE LINE:  'Show Dialog Button Programatic Dialog \(3 second delay\) Button Show TabContainer Dialog Button Test slow loading HREF Dialog Button Show File Dialog Button'",
      "     VISIBLE:  'Show TabContainer Dialog Button ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show TabContainer Dialog button'"]))
 
 ########################################################################
@@ -75,8 +72,7 @@ sequence.append(utils.AssertPresentationAction(
     "Launch dialog", 
     ["BRAILLE LINE:  'First tab Page Second tab Page'",
      "     VISIBLE:  'First tab Page Second tab Page', cursor=1",
-     "SPEECH OUTPUT: 'TabContainer Dialog dialog'",
-     "SPEECH OUTPUT: 'First tab page'"]))
+     "SPEECH OUTPUT: 'TabContainer Dialog dialog First tab page'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  
@@ -89,10 +85,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic whereAmI", 
     ["BRAILLE LINE:  'First tab Page Second tab Page'",
      "     VISIBLE:  'First tab Page Second tab Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'First tab page'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list First tab page item 1 of 2 '"]))
 
 ########################################################################
 # Close the dialog, focus goes back to button.  
@@ -104,7 +97,6 @@ sequence.append(utils.AssertPresentationAction(
     "close dialog", 
     ["BRAILLE LINE:  'Show Dialog Button Programatic Dialog \(3 second delay\) Button Show TabContainer Dialog Button Test slow loading HREF Dialog Button Show File Dialog Button'",
      "     VISIBLE:  'Show TabContainer Dialog Button ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show TabContainer Dialog button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/dojo_panel_text.py b/test/keystrokes/firefox/dojo_panel_text.py
index 519d5c6..ed4bb7f 100644
--- a/test/keystrokes/firefox/dojo_panel_text.py
+++ b/test/keystrokes/firefox/dojo_panel_text.py
@@ -34,8 +34,7 @@ sequence.append(utils.AssertPresentationAction(
     "Space to press the Show TabContainer Dialog", 
     ["BRAILLE LINE:  'First tab Page Image Second tab Page Image'",
      "     VISIBLE:  'First tab Page Image Second tab ', cursor=1",
-     "SPEECH OUTPUT: 'TabContainer Dialog dialog'",
-     "SPEECH OUTPUT: 'First tab page'"]))
+     "SPEECH OUTPUT: 'TabContainer Dialog dialog First tab page'"]))
 
 ########################################################################
 # Right Arrow to the Second tab page
@@ -46,7 +45,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to the Second tab page", 
     ["BRAILLE LINE:  'First tab Page Image Second tab Page Image'",
      "     VISIBLE:  'Second tab Page Image', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Second tab page'"]))
 
 ########################################################################
@@ -59,7 +57,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Speech isn't getting the first line",
      "BRAILLE LINE:  'This is the second tab.'",
      "     VISIBLE:  'This is the second tab.', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'panel'"]))
 
 ########################################################################
@@ -171,7 +168,6 @@ sequence.append(utils.AssertPresentationAction(
     "Escape to dismiss the dialog", 
     ["BRAILLE LINE:  'Show TabContainer Dialog Button'",
      "     VISIBLE:  'Show TabContainer Dialog Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show TabContainer Dialog button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/dojo_slider.py b/test/keystrokes/firefox/dojo_slider.py
index 9c6b452..0dea599 100644
--- a/test/keystrokes/firefox/dojo_slider.py
+++ b/test/keystrokes/firefox/dojo_slider.py
@@ -43,8 +43,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to first slider", 
     ["BRAILLE LINE:  'Horizontal Slider Example 10 Slider'",
      "     VISIBLE:  'Horizontal Slider Example 10 Sli', cursor=1",
-     "SPEECH OUTPUT: 'Horizontal Slider Example table'",
-     "SPEECH OUTPUT: 'Horizontal Slider Example slider 10'"]))
+     "SPEECH OUTPUT: 'Horizontal Slider Example table Horizontal Slider Example slider 10'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  The following should be
@@ -204,8 +203,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '10.0% $l rdonly', cursor=0",
      "BRAILLE LINE:  '10.0% $l rdonly'",
      "     VISIBLE:  '10.0% $l rdonly', cursor=0",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Slider1 Value: read only text 10.0%'"]))
+     "SPEECH OUTPUT: 'Slider1 Value: read only text 10.0% selected'"]))
 
 ########################################################################
 # Tab to the button between the sliders.  
@@ -216,7 +214,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to button", 
     ["BRAILLE LINE:  'Disable previous slider Button Enable previous slider Button'",
      "     VISIBLE:  'Disable previous slider Button E', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Disable previous slider button'"]))
      
 ########################################################################
@@ -228,8 +225,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to second slider", 
     ["BRAILLE LINE:  'Vertical Slider Example 10 Slider'",
      "     VISIBLE:  'Vertical Slider Example 10 Slide', cursor=1",
-     "SPEECH OUTPUT: 'Vertical Slider Example table'",
-     "SPEECH OUTPUT: 'Vertical Slider Example slider 10'"]))
+     "SPEECH OUTPUT: 'Vertical Slider Example table Vertical Slider Example slider 10'"]))
 
 ########################################################################
 # Move the slider several times
diff --git a/test/keystrokes/firefox/dojo_spinner.py b/test/keystrokes/firefox/dojo_spinner.py
index 345dd1e..474821d 100644
--- a/test/keystrokes/firefox/dojo_spinner.py
+++ b/test/keystrokes/firefox/dojo_spinner.py
@@ -42,8 +42,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - The spinbox is followed by some text - 'onChange:' followed by a grayed out entry containing the text 'not fired yet!'. Either the 'on change' text should be present or, in my opinion, this 'not fired yet!' removed. This is true for all assertions.",
      "BRAILLE LINE:  'Spinbox #1: 900 $l not fired yet! $l'",
      "     VISIBLE:  'Spinbox #1: 900 $l not fired yet', cursor=16",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Spinbox #1: 900 selected spin button'"]))
+     "SPEECH OUTPUT: 'Spinbox #1: 900 selected spin button required'"]))
 
 ########################################################################
 # Use down arrow to decrement spinner value.  
@@ -211,10 +210,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Spinbox #1: 902 $l not fired yet! $l'",
      "     VISIBLE:  'Spinbox #1: 902 $l not fired yet', cursor=16",
-     "SPEECH OUTPUT: 'Spinbox #1:'",
-     "SPEECH OUTPUT: 'spin button'",
-     "SPEECH OUTPUT: '902'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Spinbox #1: spin button 902 '"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/dojo_tabcontainer.py b/test/keystrokes/firefox/dojo_tabcontainer.py
index 8717ffc..aeaea24 100644
--- a/test/keystrokes/firefox/dojo_tabcontainer.py
+++ b/test/keystrokes/firefox/dojo_tabcontainer.py
@@ -38,7 +38,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to tab 2", 
     ["BRAILLE LINE:  'Tab 1 Page Tab 2 Page Tab 3 Page Inlined Sub TabContainer Page Sub TabContainer from href Page SplitContainer from href Page'",
      "     VISIBLE:  'Tab 2 Page Tab 3 Page Inlined Su', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab 2 page'"]))
 
 ########################################################################
@@ -51,10 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Tab 1 Page Tab 2 Page Tab 3 Page Inlined Sub TabContainer Page Sub TabContainer from href Page SplitContainer from href Page'",
      "     VISIBLE:  'Tab 2 Page Tab 3 Page Inlined Su', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Tab 2 page'",
-     "SPEECH OUTPUT: 'item 2 of 6'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Tab 2 page item 2 of 6 '"]))
 
 ########################################################################
 # Use arrows to move between tabs: 'Tab 3'.  The following will be presented.
@@ -65,8 +61,8 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to tab 3", 
     ["BRAILLE LINE:  'Tab 1 Page Tab 2 Page Tab 3 Page Inlined Sub TabContainer Page Sub TabContainer from href Page SplitContainer from href Page'",
      "     VISIBLE:  'Tab 3 Page Inlined Sub TabContai', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab 3 page'"]))
+
 ########################################################################
 # Use arrows to move between tabs: 'Another Tab'.  The following will be presented.
 #
@@ -76,7 +72,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to programmatically created tab", 
     ["BRAILLE LINE:  'Tab 1 Page Tab 2 Page Tab 3 Page Inlined Sub TabContainer Page Sub TabContainer from href Page SplitContainer from href Page'",
      "     VISIBLE:  'Inlined Sub TabContainer Page Su', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Inlined Sub TabContainer page'"]))
 
 ########################################################################
@@ -89,7 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to sub tab container", 
     ["BRAILLE LINE:  'Tab 1 Page Tab 2 Page Tab 3 Page Inlined Sub TabContainer Page Sub TabContainer from href Page SplitContainer from href Page'",
      "     VISIBLE:  'Sub TabContainer from href Page ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Sub TabContainer from href page'",
      "SPEECH OUTPUT: 'Subtab #1  This is a nested tab container BUT loaded via an href.'"]))
 
@@ -102,7 +96,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to tab 2 contents", 
     ["BRAILLE LINE:  'Subtab #1 Page Subtab #2 Page'",
      "     VISIBLE:  'Subtab #1 Page Subtab #2 Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Subtab #1 page'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/dojo_tree.py b/test/keystrokes/firefox/dojo_tree.py
index 8d4d526..359b804 100644
--- a/test/keystrokes/firefox/dojo_tree.py
+++ b/test/keystrokes/firefox/dojo_tree.py
@@ -39,9 +39,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to continents", 
     ["BRAILLE LINE:  'Continents ListItem'",
      "     VISIBLE:  'Continents ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Continents expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Continents expanded tree level 1'"]))
 
 ########################################################################
 # Arrow to Africa tree item
@@ -52,9 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Africa", 
     ["BRAILLE LINE:  'Africa ListItem'",
      "     VISIBLE:  'Africa ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Africa collapsed'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Africa collapsed tree level 2'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  
@@ -66,11 +62,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Africa ListItem'",
      "     VISIBLE:  'Africa ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Africa'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'list item Africa  collapsed tree level 2'"]))
 
 ########################################################################
 # Use arrows to expand/collapse/navigate tree.  
@@ -90,9 +82,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Egypt", 
     ["BRAILLE LINE:  'Egypt ListItem'",
      "     VISIBLE:  'Egypt ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Egypt'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'Egypt tree level 3'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -101,7 +91,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Kenya", 
     ["BRAILLE LINE:  'Kenya ListItem'",
      "     VISIBLE:  'Kenya ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Kenya collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -126,7 +115,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Sudan", 
     ["BRAILLE LINE:  'Sudan ListItem'",
      "     VISIBLE:  'Sudan ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Sudan collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -135,9 +123,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Asia", 
     ["BRAILLE LINE:  'Asia ListItem'",
      "     VISIBLE:  'Asia ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Asia collapsed'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Asia collapsed tree level 2'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
@@ -153,9 +139,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to China", 
     ["BRAILLE LINE:  'China ListItem'",
      "     VISIBLE:  'China ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'China'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'China tree level 3'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -163,7 +147,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to India", 
     ["BRAILLE LINE:  'India ListItem'",
      "     VISIBLE:  'India ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'India'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -172,7 +155,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Russia", 
     ["BRAILLE LINE:  'Russia ListItem'",
      "     VISIBLE:  'Russia ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Russia'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -181,7 +163,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to Mongolia", 
     ["BRAILLE LINE:  'Mongolia ListItem'",
      "     VISIBLE:  'Mongolia ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Mongolia'"]))
     
 ########################################################################
diff --git a/test/keystrokes/firefox/find_wiki.py b/test/keystrokes/firefox/find_wiki.py
index 6013f05..bfa47ea 100644
--- a/test/keystrokes/firefox/find_wiki.py
+++ b/test/keystrokes/firefox/find_wiki.py
@@ -48,10 +48,9 @@ sequence.append(KeyComboAction("<Control>F"))
 sequence.append(utils.AssertPresentationAction(
     "Get into the Find Toolbar", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Orca - GNOME Live! - " + utils.firefoxFrameNames + " Frame ToolBar  \$l'",
-     "     VISIBLE:  ' $l', cursor=1",
+     "     VISIBLE:  ' $l', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Orca - GNOME Live! - " + utils.firefoxFrameNames + " Frame ToolBar  \$l'",
-     "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: ''",
+     "     VISIBLE:  ' $l', cursor=1",
      "SPEECH OUTPUT: 'Find: text '"]))
 
 # We won't use an assert here because different builds of Firefox give
diff --git a/test/keystrokes/firefox/flat_review_combo_box.py b/test/keystrokes/firefox/flat_review_combo_box.py
index 44ab822..d1454ad 100644
--- a/test/keystrokes/firefox/flat_review_combo_box.py
+++ b/test/keystrokes/firefox/flat_review_combo_box.py
@@ -35,8 +35,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
     "Top of file", 
-    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
-     "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
+    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
+     "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
      "SPEECH OUTPUT: 'Severity link : Severity normal combo box'"]))
 
 ########################################################################
@@ -46,9 +46,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to Severity combo box", 
-    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
+    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
      "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Severity link'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/html_role_combo_box.py b/test/keystrokes/firefox/html_role_combo_box.py
index 2e2501c..0d1ae86 100644
--- a/test/keystrokes/firefox/html_role_combo_box.py
+++ b/test/keystrokes/firefox/html_role_combo_box.py
@@ -35,8 +35,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
     "Top of file", 
-    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
-     "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
+    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
+     "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
      "SPEECH OUTPUT: 'Severity link : Severity normal combo box'"]))
 
 ########################################################################
@@ -46,9 +46,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to Severity combo box", 
-    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
+    ["BRAILLE LINE:  'Severity: Severity normal Combo'",
      "     VISIBLE:  'Severity: Severity normal Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Severity link'"]))
 
 ########################################################################
@@ -61,9 +60,8 @@ sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_COMBO_BOX))
 sequence.append(utils.AssertPresentationAction(
     "Tab to Severity combo box", 
     ["BUG? - Where should the cursor be? If we're not IN the combo box should it be as is with the label showing or not?",
-     "BRAILLE LINE:  'Severity: Severity normal Combo'",
-     "     VISIBLE:  'Severity: Severity normal Combo', cursor=20",
-     "SPEECH OUTPUT: ''",
+     "BRAILLE LINE:  'Severity: Severity normal Combo'",
+     "     VISIBLE:  'Severity: Severity normal Combo', cursor=20",
      "SPEECH OUTPUT: 'Severity normal combo box'"]))
 
 ########################################################################
@@ -74,9 +72,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to Priority Link", 
-    ["BRAILLE LINE:  'Priority: Normal Combo'",
+    ["BRAILLE LINE:  'Priority: Normal Combo'",
      "     VISIBLE:  'Priority: Normal Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Priority link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -84,9 +81,8 @@ sequence.append(KeyComboAction("Tab"))
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_COMBO_BOX))
 sequence.append(utils.AssertPresentationAction(
     "Tab to Priority combo box", 
-    ["BRAILLE LINE:  'Priority: Normal Combo'",
-     "     VISIBLE:  'Priority: Normal Combo', cursor=11",
-     "SPEECH OUTPUT: ''",
+    ["BRAILLE LINE:  'Priority: Normal Combo'",
+     "     VISIBLE:  'Priority: Normal Combo', cursor=11",
      "SPEECH OUTPUT: 'Priority: Normal combo box'"]))
 
 ########################################################################
@@ -98,7 +94,6 @@ sequence.append(utils.AssertPresentationAction(
     "Change selection Down: Low",
     ["BRAILLE LINE:  'Low'",
      "     VISIBLE:  'Low', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Low'"]))
 
 ########################################################################
@@ -110,7 +105,6 @@ sequence.append(utils.AssertPresentationAction(
     "Change selection Up: Normal",
     ["BRAILLE LINE:  'Normal'",
      "     VISIBLE:  'Normal', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Normal'"]))
 
 ########################################################################
@@ -124,9 +118,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Priority: Normal Combo', cursor=0",
      "BRAILLE LINE:  'Normal'",
      "     VISIBLE:  'Normal', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Normal combo box'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Normal'"]))
 
 ########################################################################
@@ -138,7 +130,6 @@ sequence.append(utils.AssertPresentationAction(
     "Change selection Down: Low",
     ["BRAILLE LINE:  'Low'",
      "     VISIBLE:  'Low', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Low'"]))
 
 ########################################################################
@@ -150,7 +141,6 @@ sequence.append(utils.AssertPresentationAction(
     "Return to collapse combo box",
     ["BRAILLE LINE:  'Priority: Low Combo'",
      "     VISIBLE:  'Priority: Low Combo', cursor=11",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Priority: Low combo box'"]))
 
 ########################################################################
@@ -161,9 +151,8 @@ sequence.append(KeyComboAction("Tab"))
 sequence.append(WaitForFocus("", acc_role=pyatspi.ROLE_COMBO_BOX))
 sequence.append(utils.AssertPresentationAction(
     "Tab",
-    ["BRAILLE LINE:  'FIXED Combo'",
-     "     VISIBLE:  'FIXED Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
+    ["BRAILLE LINE:  'FIXED Combo'",
+     "     VISIBLE:  'FIXED Combo', cursor=1",
      "SPEECH OUTPUT: 'Resolution: FIXED combo box'"]))
 
 ########################################################################
@@ -224,9 +213,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Speech Combo', cursor=0",
      "BRAILLE LINE:  'Speech'",
      "     VISIBLE:  'Speech', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Speech combo box'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Speech'"]))
 
 ########################################################################
@@ -238,7 +225,6 @@ sequence.append(utils.AssertPresentationAction(
     "Change selection Down", 
     ["BRAILLE LINE:  'Braille'",
      "     VISIBLE:  'Braille', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Braille'"]))
 
 ########################################################################
@@ -250,7 +236,6 @@ sequence.append(utils.AssertPresentationAction(
     "Return to collapse combo box",
     ["BRAILLE LINE:  'Braille Combo'",
      "     VISIBLE:  'Braille Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Component Braille combo box'"]))
 
 ########################################################################
@@ -263,11 +248,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  'Braille Combo'",
      "     VISIBLE:  'Braille Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'combo box'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'combo box   '"]))
 
 ########################################################################
 # Press Shift Tab once to return to the Version combo box.  
@@ -276,9 +257,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Shift Tab to Version", 
-    ["BRAILLE LINE:  'Version 2.16 Combo'",
-     "     VISIBLE:  'Version 2.16 Combo', cursor=9",
-     "SPEECH OUTPUT: ''",
+    ["BRAILLE LINE:  'Version 2.16 Combo'",
+     "     VISIBLE:  'Version 2.16 Combo', cursor=9",
      "SPEECH OUTPUT: 'Version 2.16 combo box'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/html_role_links.py b/test/keystrokes/firefox/html_role_links.py
index 3142a5b..c4b9043 100644
--- a/test/keystrokes/firefox/html_role_links.py
+++ b/test/keystrokes/firefox/html_role_links.py
@@ -46,9 +46,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to anchors.html link", 
-    ["BRAILLE LINE:  'â?¢ anchors.html'",
+    ["BRAILLE LINE:  'â?¢ anchors.html'",
      "     VISIBLE:  'â?¢ anchors.html', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'anchors.html link'"]))
 
 ########################################################################
@@ -58,9 +57,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to blockquotes.html link", 
-    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
+    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
      "     VISIBLE:  'â?¢ blockquotes.html', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'blockquotes.html link'"]))
 
 ########################################################################
@@ -70,9 +68,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Tab to bugzilla_top.html link", 
-    ["BRAILLE LINE:  'â?¢ bugzilla_top.html'",
+    ["BRAILLE LINE:  'â?¢ bugzilla_top.html'",
      "     VISIBLE:  'â?¢ bugzilla_top.html', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'bugzilla_top.html link'"]))
 
 ########################################################################
@@ -82,9 +79,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>Tab"))
 sequence.append(utils.AssertPresentationAction(
     "Shift Tab to blockquotes.html link", 
-    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
+    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
      "     VISIBLE:  'â?¢ blockquotes.html', cursor=3",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'blockquotes.html link'"]))
 
 ########################################################################
@@ -96,11 +92,9 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
-    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
-     "     VISIBLE:  'â?¢ blockquotes.html', cursor=3",
-     "SPEECH OUTPUT: 'file link to blockquotes.html'",
-     "SPEECH OUTPUT: 'same site'",
-     "SPEECH OUTPUT: '1188 bytes'"]))
+    ["BRAILLE LINE:  'â?¢ blockquotes.html'",
+     "     VISIBLE:  'â?¢ blockquotes.html', cursor=3",
+     "SPEECH OUTPUT: 'file link to blockquotes.html same site 1188 bytes'"]))
 
 ########################################################################
 # Press Return to follow the blockquotes.html link.
@@ -128,8 +122,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
 sequence.append(utils.AssertPresentationAction(
     "Line Up to anchors.html", 
-    ["BRAILLE LINE:  'â?¢ anchors.html'",
-     "     VISIBLE:  'â?¢ anchors.html', cursor=1",
+    ["BRAILLE LINE:  'â?¢ anchors.html'",
+     "     VISIBLE:  'â?¢ anchors.html', cursor=1",
      "SPEECH OUTPUT: 'â?¢ anchors.html link'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/html_role_lists.py b/test/keystrokes/firefox/html_role_lists.py
index 23ff915..c3331ce 100644
--- a/test/keystrokes/firefox/html_role_lists.py
+++ b/test/keystrokes/firefox/html_role_lists.py
@@ -35,8 +35,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
     "Top of file", 
-    ["BRAILLE LINE:  'Welcome to a List of Lists h1'",
-     "     VISIBLE:  'Welcome to a List of Lists h1', cursor=1",
+    ["BRAILLE LINE:  'Welcome to a List of Lists h1'",
+     "     VISIBLE:  'Welcome to a List of Lists h1', cursor=1",
      "SPEECH OUTPUT: 'Welcome to a List of Lists heading level 1'"]))
 
 ########################################################################
@@ -46,8 +46,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
 sequence.append(utils.AssertPresentationAction(
     "Line Down", 
-    ["BRAILLE LINE:  'Lists are not only fun to make, they are fun to use. They help us:'",
-     "     VISIBLE:  'Lists are not only fun to make, ', cursor=1",
+    ["BRAILLE LINE:  'Lists are not only fun to make, they are fun to use. They help us:'",
+     "     VISIBLE:  'Lists are not only fun to make, ', cursor=1",
      "SPEECH OUTPUT: 'Lists are not only fun to make, they are fun to use. They help us:'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -164,9 +164,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  'ix. or small roman numerals'",
      "     VISIBLE:  'ix. or small roman numerals', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'ix. or small roman numerals'",
-     "SPEECH OUTPUT: 'item 4 of 6'"]))
+     "SPEECH OUTPUT: 'list item ix. or small roman numerals item 4 of 6'"]))
 
 ########################################################################
 # Move to the location bar by pressing Control+L.  When it has focus
diff --git a/test/keystrokes/firefox/html_struct_nav_blockquote.py b/test/keystrokes/firefox/html_struct_nav_blockquote.py
index 38ea875..cf91489 100644
--- a/test/keystrokes/firefox/html_struct_nav_blockquote.py
+++ b/test/keystrokes/firefox/html_struct_nav_blockquote.py
@@ -37,8 +37,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Control>Home"))
 sequence.append(utils.AssertPresentationAction(
     "Top of file", 
-    ["BRAILLE LINE:  'On weaponry:'",
-     "     VISIBLE:  'On weaponry:', cursor=1",
+    ["BRAILLE LINE:  'On weaponry:'",
+     "     VISIBLE:  'On weaponry:', cursor=1",
      "SPEECH OUTPUT: 'On weaponry:'"]))
 
 ########################################################################
@@ -73,8 +73,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("q"))
 sequence.append(utils.AssertPresentationAction(
     "q to third quote", 
-    ["BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'",
-     "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
+    ["BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'",
+     "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
      "SPEECH OUTPUT: 'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'"]))
 
 ########################################################################
@@ -100,9 +100,9 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("<Shift>q"))
 sequence.append(utils.AssertPresentationAction(
     "Shift+q wrap to bottom", 
-    ["BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'",
-     "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
-     "SPEECH OUTPUT: 'Wrapping to bottom.'",
+    ["BRAILLE LINE:  'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'",
+     "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=1",
+     "SPEECH OUTPUT: 'Wrapping to bottom.'",
      "SPEECH OUTPUT: 'Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR!'"]))
 
 ########################################################################
@@ -126,10 +126,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I",
     ["BRAILLE LINE:  'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall'",
      "     VISIBLE:  'Now old lady, you have one last ', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'paragraph'",
-     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall '",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall '"]))
 
 ########################################################################
 # Move to the location bar by pressing Control+L.  When it has focus
diff --git a/test/keystrokes/firefox/imagemap.py b/test/keystrokes/firefox/imagemap.py
index e5fba0f..901f3ec 100644
--- a/test/keystrokes/firefox/imagemap.py
+++ b/test/keystrokes/firefox/imagemap.py
@@ -48,7 +48,6 @@ sequence.append(utils.AssertPresentationAction(
     "2. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'z y x w v u t s r q p o n m l k ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'z link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -58,7 +57,6 @@ sequence.append(utils.AssertPresentationAction(
     "3. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'y x w v u t s r q p o n m l k j ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'y link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -68,7 +66,6 @@ sequence.append(utils.AssertPresentationAction(
     "4. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'x w v u t s r q p o n m l k j i ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'x link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -78,7 +75,6 @@ sequence.append(utils.AssertPresentationAction(
     "5. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'w v u t s r q p o n m l k j i h ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'w link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -88,7 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "6. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'v u t s r q p o n m l k j i h g ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'v link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -98,7 +93,6 @@ sequence.append(utils.AssertPresentationAction(
     "7. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'u t s r q p o n m l k j i h g f ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'u link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -108,7 +102,6 @@ sequence.append(utils.AssertPresentationAction(
     "8. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  't s r q p o n m l k j i h g f e ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 't link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -118,7 +111,6 @@ sequence.append(utils.AssertPresentationAction(
     "9. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  's r q p o n m l k j i h g f e d ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 's link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -128,7 +120,6 @@ sequence.append(utils.AssertPresentationAction(
     "10. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'r q p o n m l k j i h g f e d c ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'r link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -138,7 +129,6 @@ sequence.append(utils.AssertPresentationAction(
     "11. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'q p o n m l k j i h g f e d c b ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'q link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -148,7 +138,6 @@ sequence.append(utils.AssertPresentationAction(
     "12. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'p o n m l k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'p link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -158,7 +147,6 @@ sequence.append(utils.AssertPresentationAction(
     "13. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'o n m l k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'o link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -168,7 +156,6 @@ sequence.append(utils.AssertPresentationAction(
     "14. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'n m l k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'n link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -178,7 +165,6 @@ sequence.append(utils.AssertPresentationAction(
     "15. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'm l k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'm link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -188,7 +174,6 @@ sequence.append(utils.AssertPresentationAction(
     "16. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'l k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'l link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -198,7 +183,6 @@ sequence.append(utils.AssertPresentationAction(
     "17. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'k j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'k link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -208,7 +192,6 @@ sequence.append(utils.AssertPresentationAction(
     "18. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'j i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'j link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -218,7 +201,6 @@ sequence.append(utils.AssertPresentationAction(
     "19. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'i h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'i link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -228,7 +210,6 @@ sequence.append(utils.AssertPresentationAction(
     "20. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'h g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'h link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -238,7 +219,6 @@ sequence.append(utils.AssertPresentationAction(
     "21. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'g f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'g link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -248,7 +228,6 @@ sequence.append(utils.AssertPresentationAction(
     "22. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'f e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'f link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -258,7 +237,6 @@ sequence.append(utils.AssertPresentationAction(
     "23. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'e d c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'e link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -268,7 +246,6 @@ sequence.append(utils.AssertPresentationAction(
     "24. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'd c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'd link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -278,7 +255,6 @@ sequence.append(utils.AssertPresentationAction(
     "25. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'c b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'c link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -288,7 +264,6 @@ sequence.append(utils.AssertPresentationAction(
     "26. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'b a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'b link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -298,7 +273,6 @@ sequence.append(utils.AssertPresentationAction(
     "27. Tab",
     ["BRAILLE LINE:  'Test: z y x w v u t s r q p o n m l k j i h g f e d c b a'",
      "     VISIBLE:  'a', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'a link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -308,7 +282,6 @@ sequence.append(utils.AssertPresentationAction(
     "28. Tab",
     ["BRAILLE LINE:  'wk09_frozenmovie Image'",
      "     VISIBLE:  'wk09_frozenmovie Image', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'wk09_frozenmovie link image'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -318,7 +291,6 @@ sequence.append(utils.AssertPresentationAction(
     "29. Tab",
     ["BRAILLE LINE:  'shop.safeway.com Rancher's Reserve'",
      "     VISIBLE:  'shop.safeway.com Rancher's Reser', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'shop.safeway.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -328,7 +300,6 @@ sequence.append(utils.AssertPresentationAction(
     "30. Tab",
     ["BRAILLE LINE:  'shop.safeway.com Rancher's Reserve'",
      "     VISIBLE:  'Rancher's Reserve', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Rancher's Reserve link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -338,7 +309,6 @@ sequence.append(utils.AssertPresentationAction(
     "31. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.vons.com www.dominicks.com w', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.vons.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -348,7 +318,6 @@ sequence.append(utils.AssertPresentationAction(
     "32. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.dominicks.com www.randalls.c', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.dominicks.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -358,7 +327,6 @@ sequence.append(utils.AssertPresentationAction(
     "33. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.randalls.com www.tomthumb.co', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.randalls.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -368,7 +336,6 @@ sequence.append(utils.AssertPresentationAction(
     "34. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.tomthumb.com www.genuardis.c', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.tomthumb.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -378,7 +345,6 @@ sequence.append(utils.AssertPresentationAction(
     "35. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.genuardis.com www.pavilions.', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.genuardis.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -388,7 +354,6 @@ sequence.append(utils.AssertPresentationAction(
     "36. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.pavilions.com www.carrsqc.co', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.pavilions.com link'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -398,7 +363,6 @@ sequence.append(utils.AssertPresentationAction(
     "37. Tab",
     ["BRAILLE LINE:  'www.vons.com www.dominicks.com www.randalls.com www.tomthumb.com www.genuardis.com www.pavilions.com www.carrsqc.com'",
      "     VISIBLE:  'www.carrsqc.com', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'www.carrsqc.com link'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/label_guess_bug_546815.py b/test/keystrokes/firefox/label_guess_bug_546815.py
index 587eb61..5f9a35f 100644
--- a/test/keystrokes/firefox/label_guess_bug_546815.py
+++ b/test/keystrokes/firefox/label_guess_bug_546815.py
@@ -89,7 +89,8 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '2. Enter your City:  $l 3. Enter your State:  $l 4. Enter your Country: US $l text field using value'",
      "     VISIBLE:  'US $l text field using value', cursor=1",
-     "SPEECH OUTPUT: '4. Enter your Country: text US'"]))
+     "SPEECH OUTPUT: '4. Enter your Country: text'",
+     "SPEECH OUTPUT: 'US' voice=uppercase"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyPressAction(0, None, "KP_Insert"))
diff --git a/test/keystrokes/firefox/label_guess_bugzilla_search.py b/test/keystrokes/firefox/label_guess_bugzilla_search.py
index 8d3307c..5d0d652 100644
--- a/test/keystrokes/firefox/label_guess_bugzilla_search.py
+++ b/test/keystrokes/firefox/label_guess_bugzilla_search.py
@@ -57,7 +57,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Summary: contains all of the words/strings Combo $l Search Button'",
      "     VISIBLE:  'contains all of the words/string', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Summary: contains all of the words/strings combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -90,7 +89,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Admin List'",
      "     VISIBLE:  'Admin List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Classification: Admin multi-select List with 8 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -101,7 +99,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'accerciser List'",
      "     VISIBLE:  'accerciser List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Product: accerciser multi-select List with 379 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -112,7 +109,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'abiscan List'",
      "     VISIBLE:  'abiscan List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Component: abiscan multi-select List with 1248 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -123,7 +119,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '0.0.1 List'",
      "     VISIBLE:  '0.0.1 List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Version: 0.0.1 multi-select List with 857 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -134,7 +129,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '--- List'",
      "     VISIBLE:  '--- List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Target Milestone: --- multi-select List with 555 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -145,7 +139,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'A Comment: contains the string Combo $l'",
      "     VISIBLE:  'contains the string Combo $l', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'A Comment: contains the string combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -166,7 +159,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Whiteboard: contains all of the words/strings Combo $l'",
      "     VISIBLE:  'contains all of the words/string', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Whiteboard: contains all of the words/strings combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -187,7 +179,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Keywords: contains all of the keywords Combo $l'",
      "     VISIBLE:  'contains all of the keywords Com', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Keywords contains all of the keywords combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -209,7 +200,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'UNCONFIRMED List'",
      "     VISIBLE:  'UNCONFIRMED List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Status: UNCONFIRMED multi-select List with 8 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -220,7 +210,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'FIXED List'",
      "     VISIBLE:  'FIXED List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Resolution: FIXED multi-select List with 12 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -231,7 +220,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'blocker List'",
      "     VISIBLE:  'blocker List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Severity: blocker multi-select List with 7 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -242,7 +230,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Immediate List'",
      "     VISIBLE:  'Immediate List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Priority: Immediate multi-select List with 5 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -253,7 +240,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'All List'",
      "     VISIBLE:  'All List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'OS: All multi-select List with 21 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -314,7 +300,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'contains Combo'",
      "     VISIBLE:  'contains Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'contains combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -385,7 +370,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'contains Combo'",
      "     VISIBLE:  'contains Combo', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'contains combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -407,7 +391,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Only include Combo bugs numbered:  $l'",
      "     VISIBLE:  'Only include Combo bugs numbered', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Only include combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -451,7 +434,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '[Bug creation] List'",
      "     VISIBLE:  '[Bug creation] List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'where one or more of the following changed: [Bug creation] multi-select List with 26 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -473,7 +455,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Unspecified List'",
      "     VISIBLE:  'Unspecified List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'GNOME version: Unspecified multi-select List with 14 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -484,7 +465,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Unspecified List'",
      "     VISIBLE:  'Unspecified List', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'GNOME target: Unspecified multi-select List with 12 items'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -496,7 +476,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  'Sort results by: Reuse same sort as last time Combo'",
      "     VISIBLE:  'Reuse same sort as last time Com', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Sort results by: Reuse same sort as last time combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -537,7 +516,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '--- Combo --- Combo  $l Or Button'",
      "     VISIBLE:  '--- Combo --- Combo  $l Or Butto', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '--- combo box'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -548,7 +526,6 @@ sequence.append(utils.AssertPresentationAction(
     "Next form field", 
     ["BRAILLE LINE:  '--- Combo --- Combo  $l Or Button'",
      "     VISIBLE:  '--- Combo  $l Or Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '--- combo box'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/line_nav_bugzilla_search.py b/test/keystrokes/firefox/line_nav_bugzilla_search.py
index 86c48da..4373f15 100644
--- a/test/keystrokes/firefox/line_nav_bugzilla_search.py
+++ b/test/keystrokes/firefox/line_nav_bugzilla_search.py
@@ -204,7 +204,8 @@ sequence.append(utils.AssertPresentationAction(
     "Line Down",
     ["BRAILLE LINE:  'List'",
      "     VISIBLE:  'List', cursor=0",
-     "SPEECH OUTPUT: 'UNCONFIRMED multi-select List with 8 items'"]))
+     "SPEECH OUTPUT: 'UNCONFIRMED' voice=uppercase",
+     "SPEECH OUTPUT: 'multi-select List with 8 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -220,7 +221,8 @@ sequence.append(utils.AssertPresentationAction(
     "Line Down",
     ["BRAILLE LINE:  'List'",
      "     VISIBLE:  'List', cursor=0",
-     "SPEECH OUTPUT: 'FIXED multi-select List with 12 items'"]))
+     "SPEECH OUTPUT: 'FIXED' voice=uppercase",
+     "SPEECH OUTPUT: 'multi-select List with 12 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -993,7 +995,8 @@ sequence.append(utils.AssertPresentationAction(
     "Line Up",
     ["BRAILLE LINE:  'List'",
      "     VISIBLE:  'List', cursor=0",
-     "SPEECH OUTPUT: 'FIXED multi-select List with 12 items'"]))
+     "SPEECH OUTPUT: 'FIXED' voice=uppercase",
+     "SPEECH OUTPUT: 'multi-select List with 12 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
@@ -1009,7 +1012,8 @@ sequence.append(utils.AssertPresentationAction(
     "Line Up",
     ["BRAILLE LINE:  'List'",
      "     VISIBLE:  'List', cursor=0",
-     "SPEECH OUTPUT: 'UNCONFIRMED multi-select List with 8 items'"]))
+     "SPEECH OUTPUT: 'UNCONFIRMED' voice=uppercase",
+     "SPEECH OUTPUT: 'multi-select List with 8 items'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/line_nav_slash_test.py b/test/keystrokes/firefox/line_nav_slash_test.py
index dd2a882..4e826c8 100644
--- a/test/keystrokes/firefox/line_nav_slash_test.py
+++ b/test/keystrokes/firefox/line_nav_slash_test.py
@@ -135,7 +135,8 @@ sequence.append(utils.AssertPresentationAction(
     "1. Line Up",
     ["BRAILLE LINE:  '& y RadioButton Some polls'",
      "     VISIBLE:  '& y RadioButton Some polls', cursor=1",
-     "SPEECH OUTPUT: 'Some polls not selected radio button'"]))
+     "SPEECH OUTPUT: 'Some polls not selected radio button'",
+     "SPEECH OUTPUT: 'Book Reviews'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/line_nav_wiki.py b/test/keystrokes/firefox/line_nav_wiki.py
index d3b14da..21ec12c 100644
--- a/test/keystrokes/firefox/line_nav_wiki.py
+++ b/test/keystrokes/firefox/line_nav_wiki.py
@@ -55,7 +55,7 @@ sequence.append(utils.AssertPresentationAction(
     "Line Down",
     ["BRAILLE LINE:  'live.gnome.org h1 Search $l Titles Button Text Button'",
      "     VISIBLE:  'live.gnome.org h1 Search $l Titl', cursor=1",
-     "SPEECH OUTPUT: 'live.gnome.org heading level 1 text Search Titles button grayed Text button grayed'"]))
+     "SPEECH OUTPUT: 'live.gnome.org heading level 1 Search: text Search Titles button grayed Text button grayed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -1492,7 +1492,7 @@ sequence.append(utils.AssertPresentationAction(
     "Line Up",
     ["BRAILLE LINE:  'live.gnome.org h1 Search $l Titles Button Text Button'",
      "     VISIBLE:  'live.gnome.org h1 Search $l Titl', cursor=1",
-     "SPEECH OUTPUT: 'live.gnome.org heading level 1 text Search Titles button grayed Text button grayed'"]))
+     "SPEECH OUTPUT: 'live.gnome.org heading level 1 Search: text Search Titles button grayed Text button grayed'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up"))
diff --git a/test/keystrokes/firefox/link_where_am_i.py b/test/keystrokes/firefox/link_where_am_i.py
index 3fda0a1..5725797 100644
--- a/test/keystrokes/firefox/link_where_am_i.py
+++ b/test/keystrokes/firefox/link_where_am_i.py
@@ -39,9 +39,7 @@ sequence.append(utils.AssertPresentationAction(
     "Where Am I on Product summary link", 
     ["BRAILLE LINE:  '3. Product summary (designed for maintainers)'",
      "     VISIBLE:  'Product summary (designed for ma', cursor=1",
-     "SPEECH OUTPUT: 'http link Product summary'",
-     "SPEECH OUTPUT: 'different site'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'http link Product summary different site '"]))
 
 ########################################################################
 # Go home tab and do a Where Am I
@@ -57,10 +55,7 @@ sequence.append(utils.AssertPresentationAction(
     "Where Am I on New bug link", 
     ["BRAILLE LINE:  'New bug · Browse · Search · Reports · Account · Admin · Help Logged In william walker sun com | Log Out'",
      "     VISIBLE:  'New bug · Browse · Search · Repo', cursor=1",
-     "SPEECH OUTPUT: 'http link New bug'",
-     "SPEECH OUTPUT: 'different site'",
-     "SPEECH OUTPUT: ''"]))
-
+     "SPEECH OUTPUT: 'http link New bug different site '"]))
 
 ########################################################################
 # Shift+Tab back to the footprint
@@ -74,9 +69,7 @@ sequence.append(utils.AssertPresentationAction(
     "Where Am I on footprint", 
     ["BRAILLE LINE:  'Home Image Bugzilla'",
      "     VISIBLE:  'Home Image Bugzilla', cursor=1",
-     "SPEECH OUTPUT: 'http link Home image'",
-     "SPEECH OUTPUT: 'different site'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'http link Home image different site '"]))
 
 ########################################################################
 # Move to the location bar by pressing Control+L.  When it has focus
diff --git a/test/keystrokes/firefox/moz_checkbox.py b/test/keystrokes/firefox/moz_checkbox.py
index 6dac411..99a704b 100644
--- a/test/keystrokes/firefox/moz_checkbox.py
+++ b/test/keystrokes/firefox/moz_checkbox.py
@@ -33,7 +33,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to first checkbox", 
     ["BRAILLE LINE:  '<x> Include decorative fruit basket CheckBox'",
      "     VISIBLE:  '<x> Include decorative fruit bas', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Include decorative fruit basket check box checked'"]))
 
 ########################################################################
@@ -56,8 +55,8 @@ sequence.append(utils.AssertPresentationAction(
     "tab to second checkbox", 
     ["BRAILLE LINE:  '<x> Invalid checkbox CheckBox'",
      "     VISIBLE:  '<x> Invalid checkbox CheckBox', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Invalid checkbox check box checked'"]))
+
 ########################################################################
 # Now, change its state.
 #
@@ -78,8 +77,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to third checkbox", 
     ["BRAILLE LINE:  '<x> Required checkbox CheckBox'",
      "     VISIBLE:  '<x> Required checkbox CheckBox', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Required checkbox check box checked'"]))
+     "SPEECH OUTPUT: 'Required checkbox check box checked required'"]))
     
 ########################################################################
 # Now, change its state.
@@ -113,8 +111,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  '<x> Required checkbox CheckBox'",
      "     VISIBLE:  '<x> Required checkbox CheckBox', cursor=1",
-     "SPEECH OUTPUT: 'Required checkbox check box checked'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Required checkbox check box checked"]))
      
 ########################################################################
 # Tab to the checkbox tristate.
@@ -125,8 +122,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to checkbox tristate", 
     ["BRAILLE LINE:  '<x> Tri-state checkbox CheckBox'",
      "     VISIBLE:  '<x> Tri-state checkbox CheckBox', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Tri-state checkbox check box checked'"]))
+     "SPEECH OUTPUT: 'Tri-state checkbox check box checked required'"]))
     
 ########################################################################
 # change checkbox tristate state three times
diff --git a/test/keystrokes/firefox/moz_menu.py b/test/keystrokes/firefox/moz_menu.py
index bf40abc..507fc10 100644
--- a/test/keystrokes/firefox/moz_menu.py
+++ b/test/keystrokes/firefox/moz_menu.py
@@ -35,7 +35,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to the menu", 
     ["BRAILLE LINE:  'Edit'",
      "     VISIBLE:  'Edit', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Edit'"]))
 
 ########################################################################
@@ -48,10 +47,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Edit'",
      "     VISIBLE:  'Edit', cursor=1",
-     "SPEECH OUTPUT: 'Edit section'",
-     "SPEECH OUTPUT: 'Edit'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 1'"]))
+     "SPEECH OUTPUT: 'Edit section Edit  item 1 of 1'"]))
 
 ########################################################################
 # Use arrows to navigate menu structure.
@@ -62,7 +58,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to View", 
     ["BRAILLE LINE:  'View'",
      "     VISIBLE:  'View', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'View'"]))
     
 sequence.append(utils.StartRecordingAction())
@@ -74,9 +69,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Themes          >', cursor=(0|1)",
      "BRAILLE LINE:  'Themes          >'",
      "     VISIBLE:  'Themes          >', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Themes          >'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -88,9 +81,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Themes          >', cursor=(0|1)",
      "BRAILLE LINE:  'Themes          > Basic Grey'",
      "     VISIBLE:  'Themes          > Basic Grey', cursor=19",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Basic Grey'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -99,7 +90,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to the blues", 
     ["BRAILLE LINE:  'The Blues'",
      "     VISIBLE:  'The Blues', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'The Blues'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -108,7 +98,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to garden", 
     ["BRAILLE LINE:  'Garden'",
      "     VISIBLE:  'Garden', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Garden'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -117,7 +106,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to in the pink", 
     ["BRAILLE LINE:  'In the Pink grayed'",
      "     VISIBLE:  'In the Pink grayed', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'In the Pink grayed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -126,7 +114,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to rose", 
     ["BRAILLE LINE:  'Rose'",
      "     VISIBLE:  'Rose', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Rose'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -135,7 +122,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move back to Themes", 
     ["BRAILLE LINE:  'Themes          >'",
      "     VISIBLE:  'Themes          >', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Themes          >'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -144,7 +130,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to hide", 
     ["BRAILLE LINE:  'Hide'",
      "     VISIBLE:  'Hide', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Hide'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -153,7 +138,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to show", 
     ["BRAILLE LINE:  'Show'",
      "     VISIBLE:  'Show', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -162,7 +146,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to more", 
     ["BRAILLE LINE:  'More                >'",
      "     VISIBLE:  'More                >', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'More                >'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -175,9 +158,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'More                >', cursor=(0|1)",
      "BRAILLE LINE:  'More                > one'",
      "     VISIBLE:  'More                > one', cursor=23",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'one'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -186,7 +167,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move to two", 
     ["BRAILLE LINE:  'two'",
      "     VISIBLE:  'two', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'two'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -196,7 +176,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Focus is being given back to the table, but should we be saying more here?",
      "BRAILLE LINE:  'Entry # ColumnHeader Date ColumnHeader Expense ColumnHeader Amount ColumnHeader Merchant ColumnHeader Type ColumnHeader'",
      "     VISIBLE:  'Entry # ColumnHeader Date Column', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'table'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/moz_progressbar.py b/test/keystrokes/firefox/moz_progressbar.py
index 310bbbf..5f15894 100644
--- a/test/keystrokes/firefox/moz_progressbar.py
+++ b/test/keystrokes/firefox/moz_progressbar.py
@@ -35,7 +35,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to button", 
     ["BRAILLE LINE:  'Load schedule  Cancel'",
      "     VISIBLE:  'Load schedule  Cancel', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Load schedule button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/moz_slider.py b/test/keystrokes/firefox/moz_slider.py
index f24e3ea..55d1a2b 100644
--- a/test/keystrokes/firefox/moz_slider.py
+++ b/test/keystrokes/firefox/moz_slider.py
@@ -32,9 +32,8 @@ sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Tab"))
 sequence.append(utils.AssertPresentationAction(
     "tab to slider", 
-    ["BRAILLE LINE:  '10% Slider",
+    ["BRAILLE LINE:  '10% Slider'",
      "     VISIBLE:  '10% Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'My slider slider 10%'"]))
 
 ########################################################################
@@ -45,13 +44,9 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
-    ["BRAILLE LINE:  '10% Slider",
+    ["BRAILLE LINE:  '10% Slider'",
      "     VISIBLE:  '10% Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'slider'",
-     "SPEECH OUTPUT: '10.0'",
-     "SPEECH OUTPUT: '10 percent'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'slider 10.0 10 percent '"]))
 
 ########################################################################
 # Move the slider several times.  The following will be presented for each.
diff --git a/test/keystrokes/firefox/moz_tabpanel.py b/test/keystrokes/firefox/moz_tabpanel.py
index 79bc3d5..8a24843 100644
--- a/test/keystrokes/firefox/moz_tabpanel.py
+++ b/test/keystrokes/firefox/moz_tabpanel.py
@@ -40,10 +40,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Zero Page Tab One Page Tab T', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Tab Zero page'",
-     "SPEECH OUTPUT: 'item 1 of 5'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Tab Zero page item 1 of 5 '"]))
 
 ########################################################################
 # Move to tab 2.
@@ -54,8 +51,8 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to tab 2", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab One Page Tab Two Page Tab Th', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab One page'"]))
+
 ########################################################################
 # Move to tab 3
 #
@@ -65,8 +62,8 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to tab 3", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Two Page Tab Three Page Tab ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab Two page'"]))
+
 ########################################################################
 # Move to tab 3 contents
 #
@@ -76,9 +73,8 @@ sequence.append(utils.AssertPresentationAction(
     "tab to tab 3 contents", 
     ["BRAILLE LINE:  '&=y RadioButton Internal Portal Bookmark & y RadioButton External URL'",
      "     VISIBLE:  '&=y RadioButton Internal Portal ', cursor=1",
-     "SPEECH OUTPUT: 'Tab Two scroll pane'",
-     "SPEECH OUTPUT: 'Internal Portal Bookmark'",
-     "SPEECH OUTPUT: 'selected radio button'"]))
+     "SPEECH OUTPUT: 'Tab Two scroll pane Internal Portal Bookmark selected radio button'"]))
+
 ########################################################################
 # Move back to tab 3
 #
@@ -88,8 +84,8 @@ sequence.append(utils.AssertPresentationAction(
     "move back to tab 3", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Two Page Tab Three Page Tab ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab Two page'"]))
+
 ########################################################################
 # Move to tab 4
 #
@@ -99,8 +95,8 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to tab 4", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Three Page Tab Four Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab Three page'"]))
+
 ########################################################################
 # Move to tab 5
 #
@@ -110,8 +106,8 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to tab 5", 
     ["BRAILLE LINE:  'Tab Zero Page Tab One Page Tab Two Page Tab Three Page Tab Four Page'",
      "     VISIBLE:  'Tab Four Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tab Four page'"]))
+
 ########################################################################
 # Close the demo
 #
diff --git a/test/keystrokes/firefox/ms_tree_bug_570571.py b/test/keystrokes/firefox/ms_tree_bug_570571.py
index 1037a39..eeb594f 100644
--- a/test/keystrokes/firefox/ms_tree_bug_570571.py
+++ b/test/keystrokes/firefox/ms_tree_bug_570571.py
@@ -36,9 +36,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Colors", 
     ["BRAILLE LINE:  '+Colors ListItem'",
      "     VISIBLE:  '+Colors ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: '+Colors collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: '+Colors collapsed tree level 1'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -51,11 +49,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - There are visually two items here, but we say this is 1 of 1",
      "BRAILLE LINE:  '+Colors ListItem'",
      "     VISIBLE:  '+Colors ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: '+Colors'",
-     "SPEECH OUTPUT: 'item 1 of 1'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'list item +Colors item 1 of 1 collapsed tree level 1'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Right"))
@@ -79,11 +73,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  '-Colors ListItem'",
      "     VISIBLE:  '-Colors ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: '-Colors'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'list item -Colors item 1 of 2 expanded tree level 1'"]))
 
 ########################################################################
 # Down Arrow. Independent of Orca, the first item claims focus as one
@@ -98,10 +88,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Red ListItem', cursor=1",
      "BRAILLE LINE:  'Blue ListItem'",
      "     VISIBLE:  'Blue ListItem', cursor=1",
-     "SPEECH OUTPUT: 'main colors panel'",
-     "SPEECH OUTPUT: 'Red'",
-     "SPEECH OUTPUT: 'tree level 2'",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'main colors panel Red tree level 2'",
      "SPEECH OUTPUT: 'Blue'"]))
 
 ########################################################################
@@ -115,11 +102,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Red ListItem', cursor=1",
      "BRAILLE LINE:  '-Colors ListItem'",
      "     VISIBLE:  '-Colors ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Red'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: '-Colors expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: '-Colors expanded tree level 1'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
@@ -142,7 +126,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Animals", 
     ["BRAILLE LINE:  '+Animals ListItem'",
      "     VISIBLE:  '+Animals ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '+Animals collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -170,9 +153,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Dog ListItem', cursor=1",
      "BRAILLE LINE:  'Cat ListItem'",
      "     VISIBLE:  'Cat ListItem', cursor=1",
-     "SPEECH OUTPUT: 'animals panel'",
-     "SPEECH OUTPUT: 'Dog'",
-     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'animals panel Dog'",
      "SPEECH OUTPUT: 'Cat'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/page_summary.py b/test/keystrokes/firefox/page_summary.py
index 745dac1..110b948 100644
--- a/test/keystrokes/firefox/page_summary.py
+++ b/test/keystrokes/firefox/page_summary.py
@@ -50,14 +50,9 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'This is a Heading 6. h6', cursor=1",
      "BRAILLE LINE:  'This is a Heading 6. h6'",
      "     VISIBLE:  'This is a Heading 6. h6', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'heading level 6'",
      "SPEECH OUTPUT: 'This is a Heading 6.'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: '14 headings'",
-     "SPEECH OUTPUT: '3 forms'",
-     "SPEECH OUTPUT: '47 tables'",
-     "SPEECH OUTPUT: '19 unvisited links'"]))
+     "SPEECH OUTPUT: '14 headings 3 forms 47 tables 19 unvisited links'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/sayAll_bugzilla_search.py b/test/keystrokes/firefox/sayAll_bugzilla_search.py
index ecc710c..ece733b 100644
--- a/test/keystrokes/firefox/sayAll_bugzilla_search.py
+++ b/test/keystrokes/firefox/sayAll_bugzilla_search.py
@@ -88,9 +88,11 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'text'",
      "SPEECH OUTPUT: 'separator'",
      "SPEECH OUTPUT: 'Status:'",
-     "SPEECH OUTPUT: 'UNCONFIRMED multi-select List with 8 items'",
+     "SPEECH OUTPUT: 'UNCONFIRMED'",
+     "SPEECH OUTPUT: 'multi-select List with 8 items'",
      "SPEECH OUTPUT: 'Resolution:'",
-     "SPEECH OUTPUT: 'FIXED multi-select List with 12 items'",
+     "SPEECH OUTPUT: 'FIXED'",
+     "SPEECH OUTPUT: 'multi-select List with 12 items'",
      "SPEECH OUTPUT: 'Severity:'",
      "SPEECH OUTPUT: 'blocker multi-select List with 7 items'",
      "SPEECH OUTPUT: 'Priority:'",
diff --git a/test/keystrokes/firefox/sayAll_role_combo_box.py b/test/keystrokes/firefox/sayAll_role_combo_box.py
index 562a6ff..567c642 100644
--- a/test/keystrokes/firefox/sayAll_role_combo_box.py
+++ b/test/keystrokes/firefox/sayAll_role_combo_box.py
@@ -48,7 +48,9 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'Priority link'",
      "SPEECH OUTPUT: ': Normal combo box'",
      "SPEECH OUTPUT: 'Resolution: ", 
-     " FIXED combo box'",
+     "'",
+     "SPEECH OUTPUT: 'FIXED'",
+     "SPEECH OUTPUT: 'combo box'",
      "SPEECH OUTPUT: 'Version'",
      "SPEECH OUTPUT: '2.16 combo box'",
      "SPEECH OUTPUT: 'Component'",
diff --git a/test/keystrokes/firefox/sayAll_wiki.py b/test/keystrokes/firefox/sayAll_wiki.py
index 2ca8dad..1d6a5a8 100644
--- a/test/keystrokes/firefox/sayAll_wiki.py
+++ b/test/keystrokes/firefox/sayAll_wiki.py
@@ -56,7 +56,7 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'Development link'",
      "SPEECH OUTPUT: 'Community link'",
      "SPEECH OUTPUT: 'live.gnome.org heading level 1'",
-     "SPEECH OUTPUT: 'text Search'",
+     "SPEECH OUTPUT: 'Search: text Search'",
      "SPEECH OUTPUT: 'Titles button grayed Text button grayed'",
      "SPEECH OUTPUT: 'Home link'",
      "SPEECH OUTPUT: 'RecentChanges link'",
@@ -121,7 +121,7 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'Immutable Page'",
      "SPEECH OUTPUT: 'Info link'",
      "SPEECH OUTPUT: 'Attachments link'",
-     "SPEECH OUTPUT: '.*combo box'",
+     "SPEECH OUTPUT: 'combo box'",
      "SPEECH OUTPUT: 'GNOME World Wide heading level 3'",
      "SPEECH OUTPUT: 'GnomeWorldWide link image'",
      "SPEECH OUTPUT: 'Copyright © 2005, 2006, 2007 The GNOME Project link .",
diff --git a/test/keystrokes/firefox/tpg_aria_slider.py b/test/keystrokes/firefox/tpg_aria_slider.py
index 74c4d85..79cd61b 100644
--- a/test/keystrokes/firefox/tpg_aria_slider.py
+++ b/test/keystrokes/firefox/tpg_aria_slider.py
@@ -36,7 +36,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Volume Slider", 
     ["BRAILLE LINE:  'Volume 0 % Slider'",
      "     VISIBLE:  'Volume 0 % Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Volume slider 0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -262,7 +261,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Food Quality Slider", 
     ["BRAILLE LINE:  'Food Quality terrible Slider'",
      "     VISIBLE:  'Food Quality terrible Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Food Quality slider terrible'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -416,7 +414,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Filesize Slider", 
     ["BRAILLE LINE:  'Filesize 0 Slider'",
      "     VISIBLE:  'Filesize 0 Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Filesize slider 0'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -569,7 +566,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Staff Slider", 
     ["BRAILLE LINE:  'The staff was helpful Strongly disagree Slider'",
      "     VISIBLE:  'The staff was helpful Strongly d', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'The staff was helpful slider Strongly disagree'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -723,7 +719,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Red Slider", 
     ["BRAILLE LINE:  'Red 0 % Slider'",
      "     VISIBLE:  'Red 0 % Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Red slider 0 %'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -951,7 +946,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Green Slider", 
     ["BRAILLE LINE:  'Green 0 Slider'",
      "     VISIBLE:  'Green 0 Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Green slider 0'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -1104,7 +1098,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Blue Slider", 
     ["BRAILLE LINE:  'Blue 0 Slider'",
      "     VISIBLE:  'Blue 0 Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Blue slider 0'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -1258,7 +1251,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to Vertical Slider", 
     ["BRAILLE LINE:  'Minimum Filesize 0 units Slider'",
      "     VISIBLE:  'Minimum Filesize 0 units Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Minimum Filesize slider 0 units'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/firefox/uiuc_alert.py b/test/keystrokes/firefox/uiuc_alert.py
index 111315a..470b6d1 100644
--- a/test/keystrokes/firefox/uiuc_alert.py
+++ b/test/keystrokes/firefox/uiuc_alert.py
@@ -40,7 +40,6 @@ sequence.append(utils.AssertPresentationAction(
     "Open Alert Box", 
     ["BRAILLE LINE:  'Alert Box'",
      "     VISIBLE:  'Alert Box', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Alert Box12 is not between 1 and 10 '"]))
 
 ########################################################################
@@ -90,8 +89,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Guess a number between 1 and 10 ', cursor=0",
      "BRAILLE LINE:  'Guess a number between 1 and 10 12 $l'",
      "     VISIBLE:  'Guess a number between 1 and 10 ', cursor=0",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Guess a number between 1 and 10 text 12'"]))
+     "SPEECH OUTPUT: 'Guess a number between 1 and 10 text 12 selected'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/uiuc_button.py b/test/keystrokes/firefox/uiuc_button.py
index 60ac063..ae35b89 100644
--- a/test/keystrokes/firefox/uiuc_button.py
+++ b/test/keystrokes/firefox/uiuc_button.py
@@ -35,8 +35,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to first button", 
     ["BRAILLE LINE:  'Font Larger + Button Font Smaller - Button &=y Italic i ToggleButton Bold B Button'",
      "     VISIBLE:  'Font Larger + Button Font Smalle', cursor=1",
-     "SPEECH OUTPUT: 'Text Formating Controls 1 list'",
-     "SPEECH OUTPUT: 'Font Larger + button'"]))
+     "SPEECH OUTPUT: 'Text Formating Controls 1 list Font Larger + button'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  The following should be
@@ -49,9 +48,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereamI", 
     ["BRAILLE LINE:  'Font Larger + Button Font Smaller - Button &=y Italic i ToggleButton Bold B Button'",
      "     VISIBLE:  'Font Larger + Button Font Smalle', cursor=1",
-     "SPEECH OUTPUT: 'Font Larger +'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Font Larger + button '"]))
 
 ########################################################################
 # Now push the first button.  The following will be presented.
@@ -72,7 +69,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to second button", 
     ["BRAILLE LINE:  'Font Larger + Button Font Smaller - Button &=y Italic i ToggleButton Bold B Button'",
      "     VISIBLE:  'Font Smaller - Button &=y Italic', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Font Smaller - button'"]))
 
 ########################################################################
@@ -93,7 +89,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to third button", 
     ["BRAILLE LINE:  'Font Larger + Button Font Smaller - Button &=y Italic i ToggleButton Bold B Button'",
      "     VISIBLE:  '&=y Italic i ToggleButton Bold B', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Italic i toggle button pressed'"]))
 
 ########################################################################
@@ -116,7 +111,6 @@ sequence.append(utils.AssertPresentationAction(
     "tab to fourth button", 
     ["BRAILLE LINE:  'Font Larger + Button Font Smaller - Button & y Italic i ToggleButton Bold B Button'",
      "     VISIBLE:  'Bold B Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bold B button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/uiuc_grid.py b/test/keystrokes/firefox/uiuc_grid.py
index 73a7c2b..7b98026 100644
--- a/test/keystrokes/firefox/uiuc_grid.py
+++ b/test/keystrokes/firefox/uiuc_grid.py
@@ -37,10 +37,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'E-mail List Sorted by Date Capti', cursor=1",
      "BRAILLE LINE:  'Email 0 Selected CheckBox 1 Cell Read message Image Attachment Image Lowest priority Image John Smith Cell Trip to Florida Cell 2007-10-03 Cell 2K Cell'",
      "     VISIBLE:  'Email 0 Selected CheckBox 1 Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'E-mail List Sorted by Date table'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Status column header'",
      "SPEECH OUTPUT: '1 Read message Attachment Lowest priority From John Smith Subject Trip to Florida panel'"]))
   
 ########################################################################
@@ -53,8 +49,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Email 0 Selected CheckBox 1 Cell Read message Image Attachment Image Lowest priority Image John Smith Cell Trip to Florida Cell 2007-10-03 Cell 2K Cell'",
      "     VISIBLE:  'Email 0 Selected CheckBox 1 Cell', cursor=1",
-     "SPEECH OUTPUT: '1 Read message Attachment Lowest priority From John Smith Subject Trip to Florida'",
-     "SPEECH OUTPUT: 'panel'",
+     "SPEECH OUTPUT: '1 Read message Attachment Lowest priority From John Smith Subject Trip to Florida panel'",
      "SPEECH OUTPUT: '1 Read message Attachment Lowest priority John Smith Trip to Florida'"]))
 
 ########################################################################
@@ -66,8 +61,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move down grid", 
     ["BRAILLE LINE:  'Email 1 Selected CheckBox 2 Cell New message Image Attachment Image Low priority Image Fred Jones Cell Lunch on Friday Cell 2007-12-03 Cell 1K Cell'",
      "     VISIBLE:  'Email 1 Selected CheckBox 2 Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Att column header'",
      "SPEECH OUTPUT: '2 New message Attachment Low priority From Fred Jones Subject Lunch on Friday panel'"]))
     
 ########################################################################
@@ -79,7 +72,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move right on second row 1", 
     ["BRAILLE LINE:  'Email 1 Selected CheckBox 2 Cell New message Image Attachment Image Low priority Image Fred Jones Cell Lunch on Friday Cell 2007-12-03 Cell 1K Cell'",
      "     VISIBLE:  'Email 1 Selected CheckBox 2 Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Email 1 Selected'"]))
      
 ########################################################################
@@ -91,7 +83,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move right on second row 2", 
     ["BRAILLE LINE:  'Email 1 Selected CheckBox 2 Cell New message Image Attachment Image Low priority Image Fred Jones Cell Lunch on Friday Cell 2007-12-03 Cell 1K Cell'",
      "     VISIBLE:  '2 Cell New message Image Attachm', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '2'"]))
      
 ########################################################################
@@ -103,7 +94,6 @@ sequence.append(utils.AssertPresentationAction(
     "Move right on second row 3", 
     ["BRAILLE LINE:  '< > Email 1 Selected CheckBox 2 New message Image Attachment Image Low priority Image Fred Jones Lunch on Friday 2007-12-03 1K'",
      "     VISIBLE:  'New message Image Attachment Ima', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New message'"]))
     
 ########################################################################
@@ -115,8 +105,7 @@ sequence.append(utils.AssertPresentationAction(
     "Move down to third row", 
     ["BRAILLE LINE:  '< > Email 2 Selected CheckBox 3 New message Image None Image Jane Johnson Proposal for you to review 2007-16-03 12K'",
      "     VISIBLE:  'New message Image None Image Jan', cursor=1",
-     "SPEECH OUTPUT: '3 New message None From Jane Johnson Subject Proposal for you to review panel'",
-     "SPEECH OUTPUT: 'New message'"]))
+     "SPEECH OUTPUT: '3 New message None From Jane Johnson Subject Proposal for you to review panel New message'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/firefox/uiuc_radiobutton.py b/test/keystrokes/firefox/uiuc_radiobutton.py
index c70b84d..372ee9c 100644
--- a/test/keystrokes/firefox/uiuc_radiobutton.py
+++ b/test/keystrokes/firefox/uiuc_radiobutton.py
@@ -35,8 +35,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to first button", 
     ["BRAILLE LINE:  '& y Thai RadioButton'",
      "     VISIBLE:  '& y Thai RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Lunch Options panel'",
-     "SPEECH OUTPUT: 'Thai not selected radio button'"]))
+     "SPEECH OUTPUT: 'Lunch Options panel Thai not selected radio button'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  The following should be
@@ -48,11 +47,8 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereamI", 
     ["BRAILLE LINE:  '& y Thai RadioButton'",
      "     VISIBLE:  '& y Thai RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Lunch Options'",
-     "SPEECH OUTPUT: 'Thai radio button'",
-     "SPEECH OUTPUT: 'not selected'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Lunch Options Thai radio button not selected  '"]))
+
 ########################################################################
 # Move to the second radio button.
 #
@@ -62,7 +58,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to second radio button", 
     ["BRAILLE LINE:  '&=y Subway RadioButton'",
      "     VISIBLE:  '&=y Subway RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Subway selected radio button'"]))
 
 ########################################################################
@@ -74,7 +69,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to third radio button", 
     ["BRAILLE LINE:  '&=y Jimmy Johns RadioButton'",
      "     VISIBLE:  '&=y Jimmy Johns RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Jimmy Johns selected radio button'"]))
 
 ########################################################################
@@ -86,7 +80,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to fourth radio button", 
     ["BRAILLE LINE:  '&=y Radio Maria RadioButton'",
      "     VISIBLE:  '&=y Radio Maria RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Radio Maria selected radio button'"]))
 
 ########################################################################
@@ -98,7 +91,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to fifth radio button", 
     ["BRAILLE LINE:  '&=y Rainbow Gardens RadioButton'",
      "     VISIBLE:  '&=y Rainbow Gardens RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Rainbow Gardens selected radio button'"]))
 
 ########################################################################
@@ -111,8 +103,7 @@ sequence.append(utils.AssertPresentationAction(
     "tab to second radio group", 
     ["BRAILLE LINE:  '&=y Coffee RadioButton'",
      "     VISIBLE:  '&=y Coffee RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Drink Options panel'",
-     "SPEECH OUTPUT: 'Coffee selected radio button'"]))
+     "SPEECH OUTPUT: 'Drink Options panel Coffee selected radio button'"]))
 
 ########################################################################
 # Move to the second radio button.
@@ -123,7 +114,6 @@ sequence.append(utils.AssertPresentationAction(
     "move to second radio button grp2",
     ["BRAILLE LINE:  '&=y Cola RadioButton'",
      "     VISIBLE:  '&=y Cola RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Cola selected radio button'"]))
 
 ########################################################################
@@ -135,7 +125,6 @@ sequence.append(utils.AssertPresentationAction(
     "move back to first radio button grp2",
     ["BRAILLE LINE:  '&=y Coffee RadioButton'",
      "     VISIBLE:  '&=y Coffee RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Coffee selected radio button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/uiuc_slider.py b/test/keystrokes/firefox/uiuc_slider.py
index a86a5ee..2e830f3 100644
--- a/test/keystrokes/firefox/uiuc_slider.py
+++ b/test/keystrokes/firefox/uiuc_slider.py
@@ -34,7 +34,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to slider 1", 
     ["BRAILLE LINE:  'Slider Control 1 50 Slider'",
      "     VISIBLE:  'Slider Control 1 50 Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Slider Control 1 slider 50'"]))
     
 ########################################################################
@@ -47,11 +46,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Slider Control 1 50 Slider'",
      "     VISIBLE:  'Slider Control 1 50 Slider', cursor=1",
-     "SPEECH OUTPUT: 'Slider Control 1'",
-     "SPEECH OUTPUT: 'slider'",
-     "SPEECH OUTPUT: '50.0'",
-     "SPEECH OUTPUT: '50 percent'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Slider Control 1 slider 50.0 50 percent '"]))
     
 ########################################################################
 # Increment slider several times
@@ -113,7 +108,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to slider 2", 
     ["BRAILLE LINE:  'Slider Control 2 100 Slider'",
      "     VISIBLE:  'Slider Control 2 100 Slider', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Slider Control 2 slider 100'"]))
     
 ########################################################################
diff --git a/test/keystrokes/firefox/uiuc_tabpanel.py b/test/keystrokes/firefox/uiuc_tabpanel.py
index cd18b4f..7035d9b 100644
--- a/test/keystrokes/firefox/uiuc_tabpanel.py
+++ b/test/keystrokes/firefox/uiuc_tabpanel.py
@@ -34,7 +34,6 @@ sequence.append(utils.AssertPresentationAction(
     "Navigate to second tab", 
     ["BRAILLE LINE:  'Crust Page Veges Page Carnivore Page Delivery Page'",
      "     VISIBLE:  'Veges Page Carnivore Page Delive', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Veges page'"]))
     
 ########################################################################
@@ -46,7 +45,6 @@ sequence.append(utils.AssertPresentationAction(
     "Navigate to third tab", 
     ["BRAILLE LINE:  'Crust Page Veges Page Carnivore Page Delivery Page'",
      "     VISIBLE:  'Carnivore Page Delivery Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Carnivore page'"]))
 
 ########################################################################
@@ -59,10 +57,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Crust Page Veges Page Carnivore Page Delivery Page'",
      "     VISIBLE:  'Carnivore Page Delivery Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Carnivore page'",
-     "SPEECH OUTPUT: 'item 3 of 4'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Carnivore page item 3 of 4 '"]))
 
 ########################################################################
 # Navigate to fourth tab
@@ -73,7 +68,6 @@ sequence.append(utils.AssertPresentationAction(
     "Navigate to fourth tab", 
     ["BRAILLE LINE:  'Crust Page Veges Page Carnivore Page Delivery Page'",
      "     VISIBLE:  'Delivery Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Delivery page'"]))
     
 ########################################################################
@@ -85,7 +79,6 @@ sequence.append(utils.AssertPresentationAction(
     "Navigate to back to third tab", 
     ["BRAILLE LINE:  'Crust Page Veges Page Carnivore Page Delivery Page'",
      "     VISIBLE:  'Carnivore Page Delivery Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Carnivore page'"]))
      
 ########################################################################
@@ -97,8 +90,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab into third page", 
     ["BRAILLE LINE:  '< > CheckBox Hamburger'",
      "     VISIBLE:  '< > CheckBox Hamburger', cursor=1",
-     "SPEECH OUTPUT: 'Carnivore scroll pane'",
-     "SPEECH OUTPUT: 'Hamburger check box not checked'"]))
+     "SPEECH OUTPUT: 'Carnivore scroll pane Hamburger check box not checked'"]))
     
 ########################################################################
 # Press the checkbox
diff --git a/test/keystrokes/firefox/uiuc_tree.py b/test/keystrokes/firefox/uiuc_tree.py
index 55bdda6..8d7e69e 100644
--- a/test/keystrokes/firefox/uiuc_tree.py
+++ b/test/keystrokes/firefox/uiuc_tree.py
@@ -38,11 +38,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Fruits ListItem', cursor=1",
      "BRAILLE LINE:  'Fruits ListItem'",
      "     VISIBLE:  'Fruits ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Foods tree'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Fruits expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Fruits expanded tree level 1'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  
@@ -54,11 +51,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Fruits ListItem'",
      "     VISIBLE:  'Fruits ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Fruits'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'list item Fruits item 1 of 2 expanded tree level 1'"]))
 
 ########################################################################
 # Navigate the tree using the arrows.  
@@ -69,9 +62,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to oranges", 
     ["BRAILLE LINE:  'Oranges ListItem'",
      "     VISIBLE:  'Oranges ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Oranges'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Oranges tree level 2'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -79,7 +70,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to pineapples", 
     ["BRAILLE LINE:  'Pineapples ListItem'",
      "     VISIBLE:  'Pineapples ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Pineapples'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -88,7 +78,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to apples", 
     ["BRAILLE LINE:  'Apples ListItem'",
      "     VISIBLE:  'Apples ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Apples collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -105,9 +94,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to macintosh", 
     ["BRAILLE LINE:  'Macintosh ListItem'",
      "     VISIBLE:  'Macintosh ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Macintosh'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'Macintosh tree level 3'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -115,7 +102,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to granny smith", 
     ["BRAILLE LINE:  'Granny Smith ListItem'",
      "     VISIBLE:  'Granny Smith ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Granny Smith collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -132,9 +118,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to washington state", 
     ["BRAILLE LINE:  'Washington State ListItem'",
      "     VISIBLE:  'Washington State ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Washington State'",
-     "SPEECH OUTPUT: 'tree level 4'"]))
+     "SPEECH OUTPUT: 'Washington State tree level 4'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -142,7 +126,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to michigan", 
     ["BRAILLE LINE:  'Michigan ListItem'",
      "     VISIBLE:  'Michigan ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Michigan'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -151,7 +134,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to new york", 
     ["BRAILLE LINE:  'New York ListItem'",
      "     VISIBLE:  'New York ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New York'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -160,9 +142,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to fuji", 
     ["BRAILLE LINE:  'Fuji ListItem'",
      "     VISIBLE:  'Fuji ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Fuji'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'Fuji tree level 3'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -170,9 +150,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to bananas", 
     ["BRAILLE LINE:  'Bananas ListItem'",
      "     VISIBLE:  'Bananas ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bananas'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Bananas tree level 2'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -180,7 +158,6 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to pears", 
     ["BRAILLE LINE:  'Pears ListItem'",
      "     VISIBLE:  'Pears ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Pears'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -189,9 +166,7 @@ sequence.append(utils.AssertPresentationAction(
     "arrow to vegetables", 
     ["BRAILLE LINE:  'Vegetables ListItem'",
      "     VISIBLE:  'Vegetables ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Vegetables expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'Vegetables expanded tree level 1'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Left"))
diff --git a/test/keystrokes/firefox/xul_role_accel_label.py b/test/keystrokes/firefox/xul_role_accel_label.py
index ef7399e..2ea4ff1 100755
--- a/test/keystrokes/firefox/xul_role_accel_label.py
+++ b/test/keystrokes/firefox/xul_role_accel_label.py
@@ -30,9 +30,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'File Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar New Window\(Control N\)'",
      "     VISIBLE:  'New Window(Control N)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New Window Control N'"]))
 
 ########################################################################
@@ -44,7 +42,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in File menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar New Tab\(Control T\)'",
      "     VISIBLE:  'New Tab\(Control T\)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New Tab Control T'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -53,7 +50,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in File menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Open Location...\(Control L\)'",
      "     VISIBLE:  'Open Location...(Control L)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Open Locationâ?¦ Control L'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -62,7 +58,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in File menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Open File...\(Control O\)'",
      "     VISIBLE:  'Open File...(Control O)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Open Fileâ?¦ Control O'"]))
 
 ########################################################################
@@ -76,11 +71,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Open File...\(Control O\)'",
      "     VISIBLE:  'Open File...(Control O)', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: 'Open Fileâ?¦'",
-     "SPEECH OUTPUT: 'Control O'",
-     "SPEECH OUTPUT: 'item 4 of [0-9]+'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'File menu Open Fileâ?¦ Control O item 4 of [0-9]+ '"]))
 
 ########################################################################
 # Dismiss the menu by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_alert.py b/test/keystrokes/firefox/xul_role_alert.py
index 569cff7..648f756 100644
--- a/test/keystrokes/firefox/xul_role_alert.py
+++ b/test/keystrokes/firefox/xul_role_alert.py
@@ -36,12 +36,10 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '[JavaScript Application] Dialog', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application \[JavaScript Application\] Dialog OK Button'",
      "     VISIBLE:  'OK Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'about:blank html content'",
      "SPEECH OUTPUT: 'about:blank page'",
      "SPEECH OUTPUT: 'about:blank html content'",
      "SPEECH OUTPUT: '[JavaScript Application] I am an alert'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'OK button'"]))
 
 ########################################################################
@@ -56,7 +54,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'about:blank HtmlPane'",
      "     VISIBLE:  'about:blank HtmlPane', cursor=1",
      "SPEECH OUTPUT: '" + utils.firefoxFrameNames + " frame'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'about:blank html content'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/xul_role_check_box.py b/test/keystrokes/firefox/xul_role_check_box.py
index aac7923..b17bca2 100755
--- a/test/keystrokes/firefox/xul_role_check_box.py
+++ b/test/keystrokes/firefox/xul_role_check_box.py
@@ -32,7 +32,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to Page Setup",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Page Setup page'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -41,7 +40,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to Options",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Options Page'",
      "     VISIBLE:  'Options Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Options page'"]))
 
 ########################################################################
@@ -53,7 +51,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to checkbox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList Options Page <x> Ignore Scaling and Shrink To Fit Page Width CheckBox'",
      "     VISIBLE:  '<x> Ignore Scaling and Shrink To', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Ignore Scaling and Shrink To Fit Page Width check box checked'"]))
 
 ########################################################################
@@ -66,8 +63,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList Options Page <x> Ignore Scaling and Shrink To Fit Page Width CheckBox'",
      "     VISIBLE:  '<x> Ignore Scaling and Shrink To', cursor=1",
-     "SPEECH OUTPUT: 'Ignore Scaling and Shrink To Fit Page Width check box checked'",
-     "SPEECH OUTPUT: 'Alt h'"]))
+     "SPEECH OUTPUT: 'Ignore Scaling and Shrink To Fit Page Width check box checked Alt h'"]))
 
 ########################################################################
 # Toggle the state of the check box by pressing Space. 
@@ -91,8 +87,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList Options Page < > Ignore Scaling and Shrink To Fit Page Width CheckBox'",
      "     VISIBLE:  '< > Ignore Scaling and Shrink To', cursor=1",
-     "SPEECH OUTPUT: 'Ignore Scaling and Shrink To Fit Page Width check box not checked'",
-     "SPEECH OUTPUT: 'Alt h'"]))
+     "SPEECH OUTPUT: 'Ignore Scaling and Shrink To Fit Page Width check box not checked Alt h'"]))
 
 ########################################################################
 # Toggle the state of the check box by pressing Space. 
diff --git a/test/keystrokes/firefox/xul_role_check_menu_item.py b/test/keystrokes/firefox/xul_role_check_menu_item.py
index 4e99638..02a80f7 100755
--- a/test/keystrokes/firefox/xul_role_check_menu_item.py
+++ b/test/keystrokes/firefox/xul_role_check_menu_item.py
@@ -24,9 +24,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'View Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Toolbars Menu'",
      "     VISIBLE:  'Toolbars Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'View menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Toolbars menu'"]))
 
 ########################################################################
@@ -39,7 +37,6 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in View menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar < > Full Screen CheckItem\(F11\)'",
      "     VISIBLE:  '< > Full Screen CheckItem(F11)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Full Screen check item not checked F11'"]))
 
 ########################################################################
@@ -53,13 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar < > Full Screen CheckItem\(F11\)'",
      "     VISIBLE:  '< > Full Screen CheckItem(F11)', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'View menu'",
-     "SPEECH OUTPUT: 'Full Screen'",
-     "SPEECH OUTPUT: 'check item'",
-     "SPEECH OUTPUT: 'not checked'",
-     "SPEECH OUTPUT: 'F11'",
-     "SPEECH OUTPUT: 'item 10 of 10'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'View menu Full Screen check item not checked F11 item 10 of 10 '"]))
 
 ########################################################################
 # Dismiss the menu by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_combo_box.py b/test/keystrokes/firefox/xul_role_combo_box.py
index 372820e..3d48d94 100644
--- a/test/keystrokes/firefox/xul_role_combo_box.py
+++ b/test/keystrokes/firefox/xul_role_combo_box.py
@@ -36,8 +36,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel When " + utils.firefoxAppNames + " starts: Show a blank page Combo'",
      "     VISIBLE:  'Show a blank page Combo', cursor=1",
-     "SPEECH OUTPUT: 'Main scroll pane Startup panel'",
-     "SPEECH OUTPUT: 'When " + utils.firefoxAppNames + " starts: Show a blank page combo box'"]))
+     "SPEECH OUTPUT: 'Main scroll pane Startup panel When " + utils.firefoxAppNames + " starts: Show a blank page combo box'"]))
 
 ########################################################################
 # Now that focus is on the combo box, arrow down to "Show my windows
@@ -51,9 +50,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Show a blank page', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow my windows and tabs from last timeWhen " + utils.firefoxAppNames + " starts:  Show my windows and tabs from last time'",
      "     VISIBLE:  'Show my windows and tabs from la', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show a blank page'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show my windows and tabs from last time'"]))
 
 ########################################################################
@@ -65,7 +62,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow my home pageWhen " + utils.firefoxAppNames + " starts:  Show my home page'",
      "     VISIBLE:  'Show my home page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show my home page'"]))
 
 ########################################################################
@@ -77,7 +73,6 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow my windows and tabs from last timeWhen " + utils.firefoxAppNames + " starts:  Show my windows and tabs from last time'",
      "     VISIBLE:  'Show my windows and tabs from la', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show my windows and tabs from last time'"]))
 
 ########################################################################
@@ -89,7 +84,6 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
      "     VISIBLE:  'Show a blank page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show a blank page'"]))
 
 ########################################################################
@@ -111,7 +105,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in expanded combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show my windows and tabs from last time'",
      "     VISIBLE:  'Show my windows and tabs from la', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show my windows and tabs from last time'"]))
 
 ########################################################################
@@ -123,7 +116,6 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in expanded combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
      "     VISIBLE:  'Show a blank page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show a blank page'"]))
 
 ########################################################################
@@ -135,8 +127,7 @@ sequence.append(utils.AssertPresentationAction(
     "Return to collapse combobox",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel When " + utils.firefoxAppNames + " starts: Show a blank page Combo'",
      "     VISIBLE:  'Show a blank page Combo', cursor=1",
-     "SPEECH OUTPUT: '" + utils.firefoxAppNames + " application " + utils.firefoxAppNames + " Preferences frame Main scroll pane Startup panel'",
-     "SPEECH OUTPUT: 'When " + utils.firefoxAppNames + " starts: Show a blank page combo box'"]))
+     "SPEECH OUTPUT: '" + utils.firefoxAppNames + " application " + utils.firefoxAppNames + " Preferences frame Main scroll pane Startup panel When " + utils.firefoxAppNames + " starts: Show a blank page combo box'"]))
 
 ########################################################################
 # Now try first letter navigation.  All of the items begin with S.
@@ -149,9 +140,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Show a blank page', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow my home pageWhen " + utils.firefoxAppNames + " starts:  Show my home page'",
      "     VISIBLE:  'Show my home page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show a blank page'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show my home page'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -160,7 +149,6 @@ sequence.append(utils.AssertPresentationAction(
     "First letter navigation with s",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
      "     VISIBLE:  'Show a blank page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Show a blank page'"]))
 
 ########################################################################
@@ -171,14 +159,9 @@ sequence.append(KeyComboAction("KP_Enter"))
 sequence.append(PauseAction(3000))
 sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
-    ["BUG? -  Techically the parent of the focused menu item (what combo boxes contain) is a menu, but in this case we presumably want to indicate that the focused item is a combo box.",
-     "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
+    ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame Main ScrollPane Startup Panel  ComboShow a blank pageWhen " + utils.firefoxAppNames + " starts:  Show a blank page'",
      "     VISIBLE:  'Show a blank page', cursor=1",
-     "SPEECH OUTPUT: 'Show a blank page menu'",
-     "SPEECH OUTPUT: 'Show a blank page'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 1'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Show a blank page combo box Show a blank page  item 1 of 1 '"]))
 
 ########################################################################
 # Press Shift+Tab to move back to the Main list item.
@@ -189,7 +172,6 @@ sequence.append(utils.AssertPresentationAction(
     "Shift+Tab to list item",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame List Main ListItem'",
      "     VISIBLE:  'Main ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Main'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/xul_role_entry.py b/test/keystrokes/firefox/xul_role_entry.py
index c0a333f..cc7a7ea 100644
--- a/test/keystrokes/firefox/xul_role_entry.py
+++ b/test/keystrokes/firefox/xul_role_entry.py
@@ -258,7 +258,6 @@ sequence.append(utils.AssertPresentationAction(
     "Alt+D to Description",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + dialogName + " Dialog  \$l'",
      "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Description: text '"]))
 
 ########################################################################
@@ -311,11 +310,8 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + dialogName + " Dialog Here is the second line. \$l'",
      "     VISIBLE:  'Here is the second line. $l', cursor=25",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'Here is the second line.",
-     "'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'text Here is the second line.",
+     "'"]))
 
 ########################################################
 # Press Escape to dismiss the dialog.  Focus should return to the
diff --git a/test/keystrokes/firefox/xul_role_list_item.py b/test/keystrokes/firefox/xul_role_list_item.py
index 105bbc0..921e51e 100755
--- a/test/keystrokes/firefox/xul_role_list_item.py
+++ b/test/keystrokes/firefox/xul_role_list_item.py
@@ -32,7 +32,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow in list",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame List Tabs ListItem'",
      "     VISIBLE:  'Tabs ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Tabs'"]))
 
 ########################################################################
@@ -44,7 +43,6 @@ sequence.append(utils.AssertPresentationAction(
     "Left Arrow in list",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame List Main ListItem'",
      "     VISIBLE:  'Main ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Main'"]))
 
 ########################################################################
@@ -57,9 +55,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxAppNames + " Preferences Frame List Main ListItem'",
      "     VISIBLE:  'Main ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Main'",
-     "SPEECH OUTPUT: 'item 1 of 7'"]))
+     "SPEECH OUTPUT: 'list item Main item 1 of 7'"]))
 
 ########################################################################
 # Dismiss the dialog by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_menu_bar.py b/test/keystrokes/firefox/xul_role_menu_bar.py
index 8bbe845..0182fb8 100644
--- a/test/keystrokes/firefox/xul_role_menu_bar.py
+++ b/test/keystrokes/firefox/xul_role_menu_bar.py
@@ -29,9 +29,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'File Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar New Window\(Control N\)'",
      "     VISIBLE:  'New Window(Control N)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New Window Control N'"]))
 
 ########################################################################
@@ -45,9 +43,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Edit Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Undo( grayed|)\(Control Z\)'",
      "     VISIBLE:  'Undo( grayed|)\(Control Z\)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Edit menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Undo( grayed|) Control Z'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -58,9 +54,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'View Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Toolbars Menu'",
      "     VISIBLE:  'Toolbars Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'View menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Toolbars menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -69,7 +63,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow on menu bar",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu <x> Navigation Toolbar CheckItem'",
      "     VISIBLE:  '<x> Navigation Toolbar CheckItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Navigation Toolbar check item checked'"]))
 
 ########################################################################
@@ -91,10 +84,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '" + utils.firefoxLocationBarNames + "  \$l', cursor=%s" % cursorPosition,
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Toolbars Menu'",
      "     VISIBLE:  'Toolbars Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '" + utils.firefoxLocationBarNames + " text '",
-     "SPEECH OUTPUT: 'View menu'",
-     "SPEECH OUTPUT: 'Toolbars menu'",]))
+     "SPEECH OUTPUT: 'View menu Toolbars menu'",]))
 
 # This seems to vary depending on whether or not something is in the
 # clipboard. Therefore, we'll check for either.
@@ -110,9 +101,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Edit Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar " + menuItem + "\(Control " + itemShortcut + "\)'",
      "     VISIBLE:  '" + menuItem + "\(Control " + itemShortcut + "\)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Edit menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: '" + menuItem + " Control " + itemShortcut + "'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/xul_role_page_tab.py b/test/keystrokes/firefox/xul_role_page_tab.py
index 332fa79..81c1fc2 100755
--- a/test/keystrokes/firefox/xul_role_page_tab.py
+++ b/test/keystrokes/firefox/xul_role_page_tab.py
@@ -33,10 +33,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'General page'",
-     "SPEECH OUTPUT: 'item 1 of [0-9]+'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list General page item 1 of [0-9]+ '"]))
 
 ########################################################################
 # Right Arrow to move to the second page tab.  
@@ -47,7 +44,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to second page tab",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Page Setup page'"]))
 
 ########################################################################
@@ -60,10 +56,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Page Setup page'",
-     "SPEECH OUTPUT: 'item 2 of [0-9]+'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of [0-9]+ '"]))
 
 ########################################################################
 # Left Arrow to move to the first page tab.  
@@ -74,7 +67,6 @@ sequence.append(utils.AssertPresentationAction(
     "Left Arrow to first page tab",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'General page'"]))
 
 ########################################################################
diff --git a/test/keystrokes/firefox/xul_role_push_button.py b/test/keystrokes/firefox/xul_role_push_button.py
index 0bbf806..a1a33ad 100755
--- a/test/keystrokes/firefox/xul_role_push_button.py
+++ b/test/keystrokes/firefox/xul_role_push_button.py
@@ -31,7 +31,6 @@ sequence.append(utils.AssertPresentationAction(
     "Shift+Tab to button",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Cancel Button'",
      "     VISIBLE:  'Cancel Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Cancel button'"]))
 
 ########################################################################
@@ -44,9 +43,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog Cancel Button'",
      "     VISIBLE:  'Cancel Button', cursor=1",
-     "SPEECH OUTPUT: 'Cancel'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: 'Alt c'"]))
+     "SPEECH OUTPUT: 'Cancel button Alt c'"]))
 
 ########################################################################
 # Dismiss the dialog by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_radio_button.py b/test/keystrokes/firefox/xul_role_radio_button.py
index a270ea5..10aadd3 100755
--- a/test/keystrokes/firefox/xul_role_radio_button.py
+++ b/test/keystrokes/firefox/xul_role_radio_button.py
@@ -31,8 +31,7 @@ sequence.append(utils.AssertPresentationAction(
     "Alt a to radio button group",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'All Pages selected radio button'"]))
+     "SPEECH OUTPUT: 'Range All Pages selected radio button'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter. 
@@ -44,11 +43,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'All Pages radio button'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'Alt a'"]))
+     "SPEECH OUTPUT: 'Range All Pages radio button selected item 1 of 3 Alt a'"]))
 
 ########################################################################
 # Down Arrow to the next radio button.
@@ -59,7 +54,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow to next radio button",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList General Page Range Filler & y Pages: RadioButton'",
      "     VISIBLE:  '& y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Pages: not selected radio button'"]))
 
 ########################################################################
@@ -72,11 +66,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Print Dialog TabList General Page Range Filler &=y Pages: RadioButton'",
      "     VISIBLE:  '&=y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'Pages: radio button'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'item 3 of 3'",
-     "SPEECH OUTPUT: 'Alt e'"]))
+     "SPEECH OUTPUT: 'Range Pages: radio button selected item 3 of 3 Alt e'"]))
 
 ########################################################################
 # Dismiss the dialog by pressing Escape and wait for the location bar
diff --git a/test/keystrokes/firefox/xul_role_radio_menu_item.py b/test/keystrokes/firefox/xul_role_radio_menu_item.py
index 0bfceab..783d63d 100755
--- a/test/keystrokes/firefox/xul_role_radio_menu_item.py
+++ b/test/keystrokes/firefox/xul_role_radio_menu_item.py
@@ -25,9 +25,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'View Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Toolbars Menu'",
      "     VISIBLE:  'Toolbars Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'View menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Toolbars menu'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -38,9 +36,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Page Style Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu & y No Style RadioItem'",
      "     VISIBLE:  '& y No Style RadioItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Page Style menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'No Style not selected radio menu item'"]))
 
 ########################################################################
@@ -54,13 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu & y No Style RadioItem'",
      "     VISIBLE:  '& y No Style RadioItem', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Page Style menu'",
-     "SPEECH OUTPUT: 'No Style'",
-     "SPEECH OUTPUT: 'radio menu item'",
-     "SPEECH OUTPUT: 'not selected'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Page Style menu No Style radio menu item not selected  item 1 of 2 '"]))
 
 ########################################################################
 # Down Arrow to the "Basic Page Style" radio menu item.
@@ -71,7 +61,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu &=y Basic Page Style RadioItem'",
      "     VISIBLE:  '&=y Basic Page Style RadioItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Basic Page Style selected radio menu item'"]))
 
 ########################################################################
@@ -85,13 +74,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar View Menu &=y Basic Page Style RadioItem'",
      "     VISIBLE:  '&=y Basic Page Style RadioItem', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Page Style menu'",
-     "SPEECH OUTPUT: 'Basic Page Style'",
-     "SPEECH OUTPUT: 'radio menu item'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 2 of 2'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Page Style menu Basic Page Style radio menu item selected  item 2 of 2 '"]))
 
 ########################################################################
 # Dismiss the "Page Style" menu by pressing Escape.
diff --git a/test/keystrokes/firefox/xul_role_tree.py b/test/keystrokes/firefox/xul_role_tree.py
index 491121d..d15cb3c 100644
--- a/test/keystrokes/firefox/xul_role_tree.py
+++ b/test/keystrokes/firefox/xul_role_tree.py
@@ -27,9 +27,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Bookmarks Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Bookmark This Page\(Control D\)'",
      "     VISIBLE:  'Bookmark This Page(Control D)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmarks menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmark This Page Control D'"]))
 
 sequence.append(PauseAction(3000))
@@ -39,7 +37,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in Bookmarks menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Organize Bookmarks...'",
      "     VISIBLE:  'Organize Bookmarks...', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Organize Bookmarksâ?¦'"]))
 
 sequence.append(KeyComboAction("Return"))
@@ -55,7 +52,6 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - We are no longer speaking the Level",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree All Bookmarks ListItem'",
      "     VISIBLE:  'All Bookmarks ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'All Bookmarks expanded'"]))
 
 ########################################################################
@@ -67,9 +63,7 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Toolbar ListItem'",
      "     VISIBLE:  'Bookmarks Toolbar ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bookmarks Toolbar collapsed'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Bookmarks Toolbar collapsed tree level 2'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Down"))
@@ -77,7 +71,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Menu ListItem'",
      "     VISIBLE:  'Bookmarks Menu ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmarks Menu collapsed'"]))
 
 ########################################################################
@@ -90,11 +83,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Menu ListItem'",
      "     VISIBLE:  'Bookmarks Menu ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Bookmarks Menu'",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'list item Bookmarks Menu item 2 of 3 collapsed tree level 2'"]))
 
 ########################################################################
 # Press Right Arrow to expand this item.
@@ -117,11 +106,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Menu ListItem'",
      "     VISIBLE:  'Bookmarks Menu ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Bookmarks Menu'",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'list item Bookmarks Menu item 2 of 3 expanded tree level 2'"]))
 
 ########################################################################
 # Press Down Arrow to give focus to the next item, Recently Bookmarked.
@@ -132,9 +117,7 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Recently Bookmarked ListItem'",
      "     VISIBLE:  'Recently Bookmarked ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Recently Bookmarked'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'Recently Bookmarked tree level 3'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter. 
@@ -146,10 +129,7 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Recently Bookmarked ListItem'",
      "     VISIBLE:  'Recently Bookmarked ListItem', cursor=1",
-     "SPEECH OUTPUT: 'list item'",
-     "SPEECH OUTPUT: 'Recently Bookmarked'",
-     "SPEECH OUTPUT: 'item 1 of 4'",
-     "SPEECH OUTPUT: 'tree level 3'"]))
+     "SPEECH OUTPUT: 'list item Recently Bookmarked item 1 of 4 tree level 3'"]))
 
 ########################################################################
 # Press Up Arrow to work back to the Bookmarks Toolbar list item.
@@ -160,9 +140,7 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Menu ListItem'",
      "     VISIBLE:  'Bookmarks Menu ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bookmarks Menu expanded'",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'Bookmarks Menu expanded tree level 2'"]))
 
 ########################################################################
 # Press Left Arrow to collapse this item.
@@ -184,7 +162,6 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree Bookmarks Toolbar ListItem'",
      "     VISIBLE:  'Bookmarks Toolbar ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmarks Toolbar collapsed'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -193,9 +170,7 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in tree",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame Tree All Bookmarks ListItem'",
      "     VISIBLE:  'All Bookmarks ListItem', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'All Bookmarks expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'All Bookmarks expanded tree level 1'"]))
 
 ########################################################################
 # Press Tab to return to the tree table that had focus initially.
@@ -206,10 +181,7 @@ sequence.append(utils.AssertPresentationAction(
     "Tab back to tree table",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame ScrollPane TreeTable Name ColumnHeader Bookmarks Toolbar   TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Toolbar   TREE LEVEL 1', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Name column header'",
-     "SPEECH OUTPUT: 'Bookmarks Toolbar  '",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'Name column header Bookmarks Toolbar blank blank not selected'"]))
 
 ########################################################################
 # Now that the Places Manager is back to its pre-explored state,
diff --git a/test/keystrokes/firefox/xul_role_tree_table.py b/test/keystrokes/firefox/xul_role_tree_table.py
index 4744783..0fd3c88 100644
--- a/test/keystrokes/firefox/xul_role_tree_table.py
+++ b/test/keystrokes/firefox/xul_role_tree_table.py
@@ -27,9 +27,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Bookmarks Menu', cursor=1",
      "BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Bookmark This Page\(Control D\)'",
      "     VISIBLE:  'Bookmark This Page(Control D)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmarks menu'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bookmark This Page Control D'"]))
 
 sequence.append(PauseAction(3000))
@@ -39,7 +37,6 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in Bookmarks menu",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application " + utils.firefoxFrameNames + " Frame ToolBar Application MenuBar Organize Bookmarks...'",
      "     VISIBLE:  'Organize Bookmarks...', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Organize Bookmarksâ?¦'"]))
 
 sequence.append(KeyComboAction("Return"))
@@ -54,8 +51,7 @@ sequence.append(utils.AssertPresentationAction(
     "Down Arrow in tree table",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame ScrollPane TreeTable Name ColumnHeader Bookmarks Menu   TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Menu   TREE LEVEL 1', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bookmarks Menu  '"]))
+     "SPEECH OUTPUT: 'Bookmarks Menu blank blank'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter. 
@@ -67,12 +63,8 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I", 
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame ScrollPane TreeTable Name ColumnHeader Bookmarks Menu TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Menu TREE LEVEL 1', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Name'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'Bookmarks Menu'",
-     "SPEECH OUTPUT: 'column 1 of 3'",
-     "SPEECH OUTPUT: 'row 2 of 3'",
+     "SPEECH OUTPUT: 'tree table Name cell Bookmarks Menu'",
+     "SPEECH OUTPUT: 'column 1 of 3 row 2 of 3'",
      "SPEECH OUTPUT: 'tree level 1'"]))
 
 ########################################################################
@@ -84,8 +76,7 @@ sequence.append(utils.AssertPresentationAction(
     "Up Arrow in tree table",
     ["BRAILLE LINE:  '" + utils.firefoxAppNames + " Application Library Frame ScrollPane TreeTable Name ColumnHeader Bookmarks Toolbar   TREE LEVEL 1'",
      "     VISIBLE:  'Bookmarks Toolbar   TREE LEVEL 1', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bookmarks Toolbar  '"]))
+     "SPEECH OUTPUT: 'Bookmarks Toolbar blank blank'"]))
 
 ########################################################################
 # Press Alt F4 to close the window.
diff --git a/test/keystrokes/firefox/xul_where_am_i_status_bar.py b/test/keystrokes/firefox/xul_where_am_i_status_bar.py
index 5ef0f5c..6139c9d 100644
--- a/test/keystrokes/firefox/xul_where_am_i_status_bar.py
+++ b/test/keystrokes/firefox/xul_where_am_i_status_bar.py
@@ -46,7 +46,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to button", 
     ["BRAILLE LINE:  'Who expects the Spanish Inquisition? Button'",
      "     VISIBLE:  'Who expects the Spanish Inquisit', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Who expects the Spanish Inquisition? button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -71,8 +70,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'Who expects the Spanish Inquisition? Button'",
      "     VISIBLE:  'Who expects the Spanish Inquisit', cursor=1",
      "SPEECH OUTPUT: 'Status Bar Regression Test - " + utils.firefoxFrameNames + "'",
-     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition!'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'NOBODY expects the Spanish Inquisition! '"]))
 
 ########################################################################
 # Press Tab to the second push button and press it with space bar.  
@@ -83,7 +81,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to button", 
     ["BRAILLE LINE:  'Our chief weapon is... Button'",
      "     VISIBLE:  'Our chief weapon is... Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Our chief weapon is... button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -108,8 +105,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'Our chief weapon is... Button'",
      "     VISIBLE:  'Our chief weapon is... Button', cursor=1",
      "SPEECH OUTPUT: 'Status Bar Regression Test - " + utils.firefoxFrameNames + "'",
-     "SPEECH OUTPUT: 'Surprise. Surprise and fear. Fear and surprise... And ruthless efficiency... And an almost fanatical devotion to the Pope... And nice red uniforms.'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Surprise. Surprise and fear. Fear and surprise... And ruthless efficiency... And an almost fanatical devotion to the Pope... And nice red uniforms. '"]))
 
 ########################################################################
 # Press Tab to the third push button and press it with space bar.  
@@ -120,7 +116,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tab to button", 
     ["BRAILLE LINE:  'Fetch the COMFY CHAIR (AKA clear out the status bar) Button'",
      "     VISIBLE:  'Fetch the COMFY CHAIR (AKA clear', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Fetch the COMFY CHAIR (AKA clear out the status bar) button'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -145,8 +140,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'Fetch the COMFY CHAIR (AKA clear out the status bar) Button'",
      "     VISIBLE:  'Fetch the COMFY CHAIR (AKA clear', cursor=1",
      "SPEECH OUTPUT: 'Status Bar Regression Test - " + utils.firefoxFrameNames + "'",
-     "SPEECH OUTPUT: 'Done'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Done '"]))
 
 ########################################################################
 # Move to the location bar by pressing Control+L.  When it has focus
diff --git a/test/keystrokes/firefox/yahoo_tab_view.py b/test/keystrokes/firefox/yahoo_tab_view.py
index 0febf2b..b4e2f92 100644
--- a/test/keystrokes/firefox/yahoo_tab_view.py
+++ b/test/keystrokes/firefox/yahoo_tab_view.py
@@ -39,8 +39,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BUG? - Ultimately we get around to announcing the page tab, but should we be speaking all of that additional information?",
      "BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Opera Page Firefox Page Explorer', cursor=1",
-     "SPEECH OUTPUT: 'Browser NewsPress the space bar or enter key to load the content of each tab. Browser News Press the space bar or enter key to load the content of each tab. tab list'",
-     "SPEECH OUTPUT: 'Opera page'"]))
+     "SPEECH OUTPUT: 'Browser NewsPress the space bar or enter key to load the content of each tab. Browser News Press the space bar or enter key to load the content of each tab. tab list Opera page'"]))
     
 ########################################################################
 # Right Arrow to the second tab
@@ -51,7 +50,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to the next tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Firefox Page Explorer Page Safar', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Firefox page'"]))
 
 ########################################################################
@@ -63,7 +61,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to the next tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Explorer Page Safari Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Explorer page'"]))
 
 ########################################################################
@@ -75,7 +72,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right Arrow to the next tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Safari Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Safari page'"]))
 
 ########################################################################
@@ -88,10 +84,7 @@ sequence.append(utils.AssertPresentationAction(
     "basic whereAmI", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Safari Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Safari page'",
-     "SPEECH OUTPUT: 'item 4 of 4'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Safari page item 4 of 4 '"]))
 
 ########################################################################
 # Left Arrow back to the third tab
@@ -102,7 +95,6 @@ sequence.append(utils.AssertPresentationAction(
     "Left Arrow to the previous tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Explorer Page Safari Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Explorer page'"]))
 
 ########################################################################
@@ -114,7 +106,6 @@ sequence.append(utils.AssertPresentationAction(
     "Left Arrow to the previous tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Firefox Page Explorer Page Safar', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Firefox page'"]))
 
 ########################################################################
@@ -126,7 +117,6 @@ sequence.append(utils.AssertPresentationAction(
     "Left Arrow to the previous tab", 
     ["BRAILLE LINE:  'Opera Page Firefox Page Explorer Page Safari Page'",
      "     VISIBLE:  'Opera Page Firefox Page Explorer', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Opera page'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_accel_label.py b/test/keystrokes/gtk-demo/role_accel_label.py
index bf7a705..a5a22b9 100644
--- a/test/keystrokes/gtk-demo/role_accel_label.py
+++ b/test/keystrokes/gtk-demo/role_accel_label.py
@@ -37,8 +37,7 @@ sequence.append(utils.AssertPresentationAction(
     "New menu item",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar New(Control n)'",
      "     VISIBLE:  'New(Control n)', cursor=1",
-     "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: 'New Control n'"]))
+     "SPEECH OUTPUT: 'File menu New Control n'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.  The following should be
@@ -51,11 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     "New menu item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar New(Control n)'",
      "     VISIBLE:  'New(Control n)', cursor=1",
-     "SPEECH OUTPUT: 'File menu'",
-     "SPEECH OUTPUT: 'New'",
-     "SPEECH OUTPUT: 'Control n'",
-     "SPEECH OUTPUT: 'item 1 of 5'",
-     "SPEECH OUTPUT: 'n'"]))
+     "SPEECH OUTPUT: 'File menu New Control n item 1 of 5 n'"]))
 
 ########################################################################
 # Now, continue on down the menu.
@@ -67,7 +62,6 @@ sequence.append(utils.AssertPresentationAction(
     "Open menu item",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar Open(Control o)'",
      "     VISIBLE:  'Open(Control o)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Open Control o'"]))
 
 ########################################################################
@@ -80,7 +74,6 @@ sequence.append(utils.AssertPresentationAction(
     "Save menu item",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar Save(Control s)'",
      "     VISIBLE:  'Save(Control s)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Save Control s'"]))
 
 ########################################################################
@@ -93,7 +86,6 @@ sequence.append(utils.AssertPresentationAction(
     "Save As... menu item",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar Save As...(Control s)'",
      "     VISIBLE:  'Save As...(Control s)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Save As... Control s'"]))
 
 ########################################################################
@@ -106,7 +98,6 @@ sequence.append(utils.AssertPresentationAction(
     "Quit menu item",
     ["BRAILLE LINE:  'gtk-demo Application UI Manager Frame MenuBar Quit(Control q)'",
      "     VISIBLE:  'Quit(Control q)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Quit Control q'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_alert.py b/test/keystrokes/gtk-demo/role_alert.py
index ca436fe..0f9005f 100644
--- a/test/keystrokes/gtk-demo/role_alert.py
+++ b/test/keystrokes/gtk-demo/role_alert.py
@@ -42,7 +42,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'OK Button', cursor=1", 
      "SPEECH OUTPUT: 'Information This message box has been popped up the following", 
      "number of times: 1'", 
-     "SPEECH OUTPUT: ''", 
      "SPEECH OUTPUT: 'OK button'"]))
 
 ########################################################################
@@ -82,7 +81,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Interactive Dialog Dialog Entry 1 Testing $l'",
      "     VISIBLE:  'Entry 1 Testing $l', cursor=16",
      "SPEECH OUTPUT: 'Interactive Dialog'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Entry 1 text Testing selected'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_check_box.py b/test/keystrokes/gtk-demo/role_check_box.py
index 942eecb..0d18bc5 100644
--- a/test/keystrokes/gtk-demo/role_check_box.py
+++ b/test/keystrokes/gtk-demo/role_check_box.py
@@ -35,8 +35,7 @@ sequence.append(utils.AssertPresentationAction(
     "Left resize check box unchecked plus panel context",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Horizontal Panel < > Resize CheckBox'",
      "     VISIBLE:  '< > Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: 'Horizontal panel'",
-     "SPEECH OUTPUT: 'Resize check box not checked'"]))
+     "SPEECH OUTPUT: 'Horizontal panel Resize check box not checked'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -48,8 +47,7 @@ sequence.append(utils.AssertPresentationAction(
     "Left resize check box unchecked Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Horizontal Panel < > Resize CheckBox'",
      "     VISIBLE:  '< > Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: 'Resize check box not checked'",
-     "SPEECH OUTPUT: 'Alt r'"]))
+     "SPEECH OUTPUT: 'Resize check box not checked Alt r'"]))
 
 ########################################################################
 # Now, change its state.
@@ -77,8 +75,7 @@ sequence.append(utils.AssertPresentationAction(
     "Left resize check box checked Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Horizontal Panel <x> Resize CheckBox'",
      "     VISIBLE:  '<x> Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: 'Resize check box checked'",
-     "SPEECH OUTPUT: 'Alt r'"]))
+     "SPEECH OUTPUT: 'Resize check box checked Alt r'"]))
 
 ########################################################################
 # Change the state back and move on to a few more check boxes.  The
@@ -104,7 +101,6 @@ sequence.append(utils.AssertPresentationAction(
     "Right resize check box checked",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Horizontal Panel <x> Resize CheckBox'",
      "     VISIBLE:  '<x> Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Resize check box checked'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -145,8 +141,7 @@ sequence.append(utils.AssertPresentationAction(
     "Top resize check box checked plus panel context",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Vertical Panel < > Resize CheckBox'",
      "     VISIBLE:  '< > Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: 'Vertical panel'",
-     "SPEECH OUTPUT: 'Resize check box not checked'"]))
+     "SPEECH OUTPUT: 'Vertical panel Resize check box not checked'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(TypeAction(" "))
@@ -181,7 +176,6 @@ sequence.append(utils.AssertPresentationAction(
     "Bottom resize check box checked",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame Vertical Panel <x> Resize CheckBox'",
      "     VISIBLE:  '<x> Resize CheckBox', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Resize check box checked'"]))
 
 sequence.append(utils.StartRecordingAction())
diff --git a/test/keystrokes/gtk-demo/role_check_menu_item.py b/test/keystrokes/gtk-demo/role_check_menu_item.py
index 5dd0f7a..0e18f0c 100644
--- a/test/keystrokes/gtk-demo/role_check_menu_item.py
+++ b/test/keystrokes/gtk-demo/role_check_menu_item.py
@@ -40,7 +40,6 @@ sequence.append(utils.AssertPresentationAction(
     "Bold check item",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar <x> Bold CheckItem(Control b)'",
      "     VISIBLE:  '<x> Bold CheckItem(Control b)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Bold check item checked Control b'"]))
 
 ########################################################################
@@ -53,13 +52,7 @@ sequence.append(utils.AssertPresentationAction(
     "Bold check item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar <x> Bold CheckItem(Control b)'",
      "     VISIBLE:  '<x> Bold CheckItem(Control b)', cursor=1",
-     "SPEECH OUTPUT: 'Preferences menu'",
-     "SPEECH OUTPUT: 'Bold'",
-     "SPEECH OUTPUT: 'check item'",
-     "SPEECH OUTPUT: 'checked'",
-     "SPEECH OUTPUT: 'Control b'",
-     "SPEECH OUTPUT: 'item 3 of 3'",
-     "SPEECH OUTPUT: 'b'"]))
+     "SPEECH OUTPUT: 'Preferences menu Bold check item checked Control b item 3 of 3 b'"]))
 
 ########################################################################
 # Dismiss the menu and close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_column_header.py b/test/keystrokes/gtk-demo/role_column_header.py
index 17b74af..d54ce12 100644
--- a/test/keystrokes/gtk-demo/role_column_header.py
+++ b/test/keystrokes/gtk-demo/role_column_header.py
@@ -50,7 +50,6 @@ sequence.append(utils.AssertPresentationAction(
     "Severity column header",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader'",
      "     VISIBLE:  'Severity ColumnHeader', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Severity column header'"]))
 
 sequence.append(utils.StartRecordingAction())
@@ -61,7 +60,6 @@ sequence.append(utils.AssertPresentationAction(
     "Description column header",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Description ColumnHeader'",
      "     VISIBLE:  'Description ColumnHeader', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Description column header'"]))
 
 ########################################################################
@@ -78,11 +76,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Table', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Description ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'scrollable notebooks and hidden ', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Description column header'",
-     "SPEECH OUTPUT: 'Fixed? check box not checked  60482 Normal scrollable notebooks and hidden tabs'"]))
+     "SPEECH OUTPUT: 'Description column header Fixed? check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
 
 ########################################################################
 # Now move to the cell to the left containing the word "Normal".
@@ -98,9 +93,7 @@ sequence.append(utils.AssertPresentationAction(
     "Normal cell",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader Normal'",
      "     VISIBLE:  'Normal', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Severity column header'",
-     "SPEECH OUTPUT: 'Normal'"]))
+     "SPEECH OUTPUT: 'Severity column header Normal'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -112,12 +105,8 @@ sequence.append(utils.AssertPresentationAction(
     "Normal cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Severity'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'"]))
+     "SPEECH OUTPUT: 'table Severity cell Normal'",
+     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -132,22 +121,11 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Severity ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  'Normal scrollable notebooks and ', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Severity'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Severity'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'column 3 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: '60482'",
-     "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'"]))
+     "SPEECH OUTPUT: 'table Severity cell Normal'",
+     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'table Severity cell Normal'",
+     "SPEECH OUTPUT: 'column 3 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
 
 ########################################################################
 # Now move to the cell to the left containing the number "60482".
@@ -163,9 +141,7 @@ sequence.append(utils.AssertPresentationAction(
     "60482 cell",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Bug number ColumnHeader 60482'",
      "     VISIBLE:  '60482', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Bug number column header'",
-     "SPEECH OUTPUT: '60482'"]))
+     "SPEECH OUTPUT: 'Bug number column header 60482'"]))
 
 ########################################################################
 # Now move to the cell to the left containing the checkbox.
@@ -181,9 +157,7 @@ sequence.append(utils.AssertPresentationAction(
     "Checkbox cell",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed?'",
      "     VISIBLE:  '< > Fixed?', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Fixed? column header'",
-     "SPEECH OUTPUT: 'check box not checked '"]))
+     "SPEECH OUTPUT: 'Fixed? column header check box not checked'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -195,12 +169,8 @@ sequence.append(utils.AssertPresentationAction(
     "Checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Fixed?'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'"]))
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
+     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -215,22 +185,11 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkListStore demo Frame ScrollPane Table Fixed? ColumnHeader < > Fixed? 60482 Normal scrollable notebooks and hidden tabs'",
      "     VISIBLE:  '< > Fixed? 60482 Normal scrollab', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Fixed?'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Fixed?'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'column 1 of 4'",
-     "SPEECH OUTPUT: 'row 1 of 14'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: '60482'",
-     "SPEECH OUTPUT: 'Normal'",
-     "SPEECH OUTPUT: 'scrollable notebooks and hidden tabs'"]))
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
+     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'table Fixed? cell check box not checked'",
+     "SPEECH OUTPUT: 'column 1 of 4 row 1 of 14'",
+     "SPEECH OUTPUT: 'check box not checked 60482 Normal scrollable notebooks and hidden tabs'"]))
  
 ########################################################################
 # Close the GtkListStore demo
diff --git a/test/keystrokes/gtk-demo/role_combo_box.py b/test/keystrokes/gtk-demo/role_combo_box.py
index ad5b17b..e5da7de 100644
--- a/test/keystrokes/gtk-demo/role_combo_box.py
+++ b/test/keystrokes/gtk-demo/role_combo_box.py
@@ -38,8 +38,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning Warning'",
      "     VISIBLE:  'Warning', cursor=1",
      "SPEECH OUTPUT: 'window'",
-     "SPEECH OUTPUT: 'Some stock icons panel'",
-     "SPEECH OUTPUT: 'Warning'"]))
+     "SPEECH OUTPUT: 'Some stock icons panel Warning'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -51,11 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     "Warning combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning Warning'",
      "     VISIBLE:  'Warning', cursor=1",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: 'Warning'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 5'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'menu Warning  item 1 of 5 '"]))
 
 ########################################################################
 # Now arrow down and select the "New" item.
@@ -67,7 +62,6 @@ sequence.append(utils.AssertPresentationAction(
     "New combo box item",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning New'",
      "     VISIBLE:  'New', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'New'"]))
 
 ########################################################################
@@ -80,11 +74,7 @@ sequence.append(utils.AssertPresentationAction(
     "New combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel  ComboWarning New'",
      "     VISIBLE:  'New', cursor=1",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: 'New'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 3 of 5'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'menu New  item 3 of 5 '"]))
 
 ########################################################################
 # Select the "New" entry and tab to the editable text combo box.  Skip
@@ -100,8 +90,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Some stock icons Panel New Combo'",
      "     VISIBLE:  'New Combo', cursor=1",
      "SPEECH OUTPUT: 'Combo boxes frame'",
-     "SPEECH OUTPUT: 'Some stock icons panel'",
-     "SPEECH OUTPUT: 'New combo box'"]))
+     "SPEECH OUTPUT: 'Some stock icons panel New combo box'"]))
 
 sequence.append(KeyComboAction("Tab"))
 sequence.append(WaitForFocus("Boston", acc_role=pyatspi.ROLE_COMBO_BOX))
@@ -116,8 +105,7 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel  $l'",
      "     VISIBLE:  ' $l', cursor=1",
-     "SPEECH OUTPUT: 'Editable panel'",
-     "SPEECH OUTPUT: 'text '"]))
+     "SPEECH OUTPUT: 'Editable panel text '"]))
 
 ########################################################################
 # Type "Four" in the text area.
@@ -154,10 +142,7 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four $l'",
      "     VISIBLE:  'Four $l', cursor=5",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'Four'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'text Four'"]))
 
 ########################################################################
 # Tab to the triangular down arrow of the editable combo box.
@@ -169,7 +154,6 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box open button",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four Combo'",
      "     VISIBLE:  'Four Combo', cursor=5",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Four combo box'"]))
 
 ########################################################################
@@ -207,7 +191,6 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box with selected text",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four $l'",
      "     VISIBLE:  'Four $l', cursor=5",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'text Four selected'"]))
 
 ########################################################################
@@ -220,11 +203,8 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box with selected text Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Four $l'",
      "     VISIBLE:  'Four $l', cursor=5",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'Four'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'text Four'",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ########################################################################
 # Tab to the triangular down arrow of the editable combo box and open
@@ -241,10 +221,12 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box menu",
     ["BRAILLE LINE:  'gtk-demo Application Window'",
      "     VISIBLE:  'gtk-demo Application Window', cursor=22",
+     "BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Menu'",
+     "     VISIBLE:  'Menu', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel  ComboFour One'",
      "     VISIBLE:  'One', cursor=1",
      "SPEECH OUTPUT: 'window'",
-     "SPEECH OUTPUT: 'Editable panel'",
+     "SPEECH OUTPUT: 'Editable panel menu'",
      "SPEECH OUTPUT: 'One'"]))
 
 ########################################################################
@@ -257,7 +239,6 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box One item",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel  ComboFour Two'",
      "     VISIBLE:  'Two', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Two'"]))
 
 ########################################################################
@@ -271,9 +252,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Combo boxes Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Two Combo'",
      "     VISIBLE:  'Two Combo', cursor=1",
-     "SPEECH OUTPUT: 'Combo boxes frame'",
-     "SPEECH OUTPUT: 'Editable panel'",
-     "SPEECH OUTPUT: 'Two combo box'"]))
+     "SPEECH OUTPUT: 'Combo boxes frame",
+     "SPEECH OUTPUT: 'Editable panel Two combo box'"]))
 
 sequence.append(KeyComboAction("<Shift>ISO_Left_Tab"))
 sequence.append(WaitForFocus(acc_role=pyatspi.ROLE_TEXT))
@@ -287,7 +267,6 @@ sequence.append(utils.AssertPresentationAction(
     "Editable text combo box Two text selected",
     ["BRAILLE LINE:  'gtk-demo Application Combo boxes Frame Editable Panel Two $l'",
      "     VISIBLE:  'Two $l', cursor=4",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'text Two selected'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_combo_box2.py b/test/keystrokes/gtk-demo/role_combo_box2.py
index f0d94fe..64a17fc 100644
--- a/test/keystrokes/gtk-demo/role_combo_box2.py
+++ b/test/keystrokes/gtk-demo/role_combo_box2.py
@@ -40,8 +40,7 @@ sequence.append(utils.AssertPresentationAction(
     "All sheets combo box item",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList Page Setup Page Layout Filler Only print: All sheets Combo'",
      "     VISIBLE:  'All sheets Combo', cursor=1",
-     "SPEECH OUTPUT: 'Layout'",
-     "SPEECH OUTPUT: 'Only print: All sheets combo box'"]))
+     "SPEECH OUTPUT: 'Layout Only print: All sheets combo box'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -53,11 +52,7 @@ sequence.append(utils.AssertPresentationAction(
     "All sheets combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList Page Setup Page Layout Filler Only print: All sheets Combo'",
      "     VISIBLE:  'All sheets Combo', cursor=1",
-     "SPEECH OUTPUT: 'Only print:'",
-     "SPEECH OUTPUT: 'combo box'",
-     "SPEECH OUTPUT: 'All sheets'",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'Alt o'"]))
+     "SPEECH OUTPUT: 'Only print: combo box All sheets item 1 of 3 Alt o'"]))
 
 ########################################################################
 # Down arrow to select the "Even sheets" item in the combo box.
@@ -85,11 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "Even sheets combo box item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList Page Setup Page Layout Filler Only print: Even sheets Combo'",
      "     VISIBLE:  'Even sheets Combo', cursor=1",
-     "SPEECH OUTPUT: 'Only print:'",
-     "SPEECH OUTPUT: 'combo box'",
-     "SPEECH OUTPUT: 'Even sheets'",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 'Alt o'"]))
+     "SPEECH OUTPUT: 'Only print: combo box Even sheets item 2 of 3 Alt o'"]))
 
 ########################################################################
 # Put things back the way they were and close the demo.
diff --git a/test/keystrokes/gtk-demo/role_dialog.py b/test/keystrokes/gtk-demo/role_dialog.py
index 7d44854..65292ba 100644
--- a/test/keystrokes/gtk-demo/role_dialog.py
+++ b/test/keystrokes/gtk-demo/role_dialog.py
@@ -43,11 +43,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'GtkExpander Dialog', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkExpander Dialog & y Details ToggleButton'",
      "     VISIBLE:  '& y Details ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Expander'",
-     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Expander tree level 1'",
      "SPEECH OUTPUT: 'GtkExpander Expander demo. Click on the triangle for details.'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Details toggle button not pressed'"]))
 
 ########################################################################
@@ -60,9 +57,7 @@ sequence.append(utils.AssertPresentationAction(
     "Dialog Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkExpander Dialog & y Details ToggleButton'",
      "     VISIBLE:  '& y Details ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'Details'",
-     "SPEECH OUTPUT: 'toggle button'",
-     "SPEECH OUTPUT: 'not pressed'"]))
+     "SPEECH OUTPUT: 'Details toggle button not pressed'"]))
 
 ########################################################################
 # Now close the demo and leave.
diff --git a/test/keystrokes/gtk-demo/role_icon.py b/test/keystrokes/gtk-demo/role_icon.py
index 769eaf8..0e95ddf 100644
--- a/test/keystrokes/gtk-demo/role_icon.py
+++ b/test/keystrokes/gtk-demo/role_icon.py
@@ -50,11 +50,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'GtkIconView demo Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane'",
      "     VISIBLE:  'LayeredPane', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Icon View Basics'",
-     "SPEECH OUTPUT: 'tree level 2'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Icon View Basics tree level 2'",
      "SPEECH OUTPUT: 'GtkIconView demo frame'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'layered pane'"]))
 
 ########################################################################
@@ -67,10 +64,7 @@ sequence.append(utils.AssertPresentationAction(
     "Layered pane Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane'",
      "     VISIBLE:  'LayeredPane', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'layered pane'",
-     "SPEECH OUTPUT: '0 of [0-9]+ items selected'",
-     "SPEECH OUTPUT: 'on item 0 of [0-9]+'"]))
+     "SPEECH OUTPUT: 'layered pane 0 of [0-9]+ items selected on item 0 of [0-9]+'"]))
 
 ########################################################################
 # Down into the icon list, finally making something be selected in the
@@ -83,9 +77,7 @@ sequence.append(utils.AssertPresentationAction(
     "bin icon",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane bin Icon'",
      "     VISIBLE:  'bin Icon', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'bin icon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'bin icon not selected'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -97,10 +89,7 @@ sequence.append(utils.AssertPresentationAction(
     "bin icon Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane bin Icon'",
      "     VISIBLE:  'bin Icon', cursor=1",
-     "SPEECH OUTPUT: 'Icon panel'",
-     "SPEECH OUTPUT: 'bin'",
-     "SPEECH OUTPUT: '[0-9] of [0-9]+ items selected'",
-     "SPEECH OUTPUT: 'on item 1 of [0-9]+'"]))
+     "SPEECH OUTPUT: 'Icon panel bin [0-9] of [0-9]+ items selected on item 1 of [0-9]+'"]))
 
 ########################################################################
 # Arrow right and wait for the next icon to be selected.
@@ -112,9 +101,7 @@ sequence.append(utils.AssertPresentationAction(
     "boot icon",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane boot Icon'",
      "     VISIBLE:  'boot Icon', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'boot icon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'boot icon not selected'"]))
 
 ########################################################################
 # Select more than one icon by doing Shift+Right.
@@ -126,9 +113,7 @@ sequence.append(utils.AssertPresentationAction(
     "icon selection",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane bin Icon'",
      "     VISIBLE:  'bin Icon', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'bin icon'",
-     "SPEECH OUTPUT: ' not selected'"]))
+     "SPEECH OUTPUT: 'bin icon not selected'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -140,10 +125,7 @@ sequence.append(utils.AssertPresentationAction(
     "icon selection Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkIconView demo Frame ScrollPane LayeredPane bin Icon'",
      "     VISIBLE:  'bin Icon', cursor=1",
-     "SPEECH OUTPUT: 'Icon panel'",
-     "SPEECH OUTPUT: 'bin'",
-     "SPEECH OUTPUT: '[0-9] of [0-9]+ items selected'",
-     "SPEECH OUTPUT: 'on item 1 of [0-9]+'"]))
+     "SPEECH OUTPUT: 'Icon panel bin [0-9] of [0-9]+ items selected on item 1 of [0-9]+'"]))
 
 ########################################################################
 # Close the GtkIconView demo window
diff --git a/test/keystrokes/gtk-demo/role_label.py b/test/keystrokes/gtk-demo/role_label.py
index cb20b29..cc7d0b6 100644
--- a/test/keystrokes/gtk-demo/role_label.py
+++ b/test/keystrokes/gtk-demo/role_label.py
@@ -49,7 +49,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'This message box has been popped', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Information Alert number of times: $l'",
      "     VISIBLE:  'number of times: $l', cursor=17",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
      "number of times: label'",
      "SPEECH OUTPUT: 'selected'"]))
@@ -65,9 +64,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Information Alert number of times: $l'",
      "     VISIBLE:  'number of times: $l', cursor=17",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'"]))
+     "number of times: selected label'"]))
 
 ########################################################################
 # Do an extended "Where Am I" via double KP_Enter.
@@ -83,13 +80,9 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Information Alert number of times: $l'",
      "     VISIBLE:  'number of times: $l', cursor=17",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'",
+     "number of times: selected label'",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'"]))
+     "number of times: selected label'"]))
 
 ########################################################################
 # Position the caret at the beginning of the label and move right one
@@ -141,9 +134,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Information Alert This message box has been popped up the following $l'",
      "     VISIBLE:  'This message box has been popped', cursor=5",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'"]))
+     "number of times: selected label'"]))
 
 ########################################################################
 # Do an extended "Where Am I" via double KP_Enter.
@@ -159,13 +150,9 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Information Alert This message box has been popped up the following $l'",
      "     VISIBLE:  'This message box has been popped', cursor=5",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'",
+     "number of times: selected label'",
      "SPEECH OUTPUT: 'This message box has been popped up the following",
-     "number of times:'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'label'"]))
+     "number of times: selected label'"]))
 
 ########################################################################
 # Arrow left to clear the selection and then do a Shift+Control+Left to
diff --git a/test/keystrokes/gtk-demo/role_menu.py b/test/keystrokes/gtk-demo/role_menu.py
index 72b7daf..faa8133 100644
--- a/test/keystrokes/gtk-demo/role_menu.py
+++ b/test/keystrokes/gtk-demo/role_menu.py
@@ -36,7 +36,6 @@ sequence.append(utils.AssertPresentationAction(
     "File menu",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame File Menu'",
      "     VISIBLE:  'File Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'File menu'"]))
 
 ########################################################################
@@ -49,12 +48,7 @@ sequence.append(utils.AssertPresentationAction(
     "File menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame File Menu'",
      "     VISIBLE:  'File Menu', cursor=1",
-     "SPEECH OUTPUT: 'menu bar'",
-     "SPEECH OUTPUT: 'File'",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'f'"]))
+     "SPEECH OUTPUT: 'menu bar File menu  item 1 of 3 f'"]))
 
 ########################################################################
 # Right arrow to the "Preferences" menu.
@@ -67,7 +61,6 @@ sequence.append(utils.AssertPresentationAction(
     "Preferences menu",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame Preferences Menu'",
      "     VISIBLE:  'Preferences Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Preferences menu'"]))
 
 ########################################################################
@@ -80,12 +73,7 @@ sequence.append(utils.AssertPresentationAction(
     "Preferences menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame Preferences Menu'",
      "     VISIBLE:  'Preferences Menu', cursor=1",
-     "SPEECH OUTPUT: 'menu bar'",
-     "SPEECH OUTPUT: 'Preferences'",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 'p'"]))
+     "SPEECH OUTPUT: 'menu bar Preferences menu  item 2 of 3 p'"]))
 
 ########################################################################
 # Go down to the "Color" menu.
@@ -98,7 +86,6 @@ sequence.append(utils.AssertPresentationAction(
     "Color menu",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Color Menu'",
      "     VISIBLE:  'Color Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Color menu'"]))
 
 ########################################################################
@@ -111,12 +98,7 @@ sequence.append(utils.AssertPresentationAction(
     "Color menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Color Menu'",
      "     VISIBLE:  'Color Menu', cursor=1",
-     "SPEECH OUTPUT: 'Preferences menu'",
-     "SPEECH OUTPUT: 'Color'",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'c'"]))
+     "SPEECH OUTPUT: 'Preferences menu Color menu  item 1 of 3 c'"]))
 
 ########################################################################
 # Go down to the "Shape" menu.
@@ -129,7 +111,6 @@ sequence.append(utils.AssertPresentationAction(
     "Shape menu",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Shape Menu'",
      "     VISIBLE:  'Shape Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Shape menu'"]))
 
 ########################################################################
@@ -142,12 +123,7 @@ sequence.append(utils.AssertPresentationAction(
     "Shape menu Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Shape Menu'",
      "     VISIBLE:  'Shape Menu', cursor=1",
-     "SPEECH OUTPUT: 'Preferences menu'",
-     "SPEECH OUTPUT: 'Shape'",
-     "SPEECH OUTPUT: 'menu'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 's'"]))
+     "SPEECH OUTPUT: 'Preferences menu Shape menu  item 2 of 3 s'"]))
 
 ########################################################################
 # Dismiss the menu and close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_page_tab.py b/test/keystrokes/gtk-demo/role_page_tab.py
index e0659c1..2984beb 100644
--- a/test/keystrokes/gtk-demo/role_page_tab.py
+++ b/test/keystrokes/gtk-demo/role_page_tab.py
@@ -41,13 +41,9 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'TabList', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Printing'",
-     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Printing tree level 1'",
      "SPEECH OUTPUT: 'Print Range Copies'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'General page'"]))
 
 ########################################################################
@@ -60,10 +56,7 @@ sequence.append(utils.AssertPresentationAction(
     "General page tab Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog General Page'",
      "     VISIBLE:  'General Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'General page'",
-     "SPEECH OUTPUT: 'item 1 of 2'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list General page item 1 of 2 '"]))
 
 ########################################################################
 # Arrow Right to the "Page Setup" tab.
@@ -75,7 +68,6 @@ sequence.append(utils.AssertPresentationAction(
     "Page Setup page tab",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Page Setup page'"]))
 
 ########################################################################
@@ -88,10 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "Page Setup page tab Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog Page Setup Page'",
      "     VISIBLE:  'Page Setup Page', cursor=1",
-     "SPEECH OUTPUT: 'tab list'",
-     "SPEECH OUTPUT: 'Page Setup page'",
-     "SPEECH OUTPUT: 'item 2 of 2'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'tab list Page Setup page item 2 of 2 '"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/gtk-demo/role_push_button.py b/test/keystrokes/gtk-demo/role_push_button.py
index d47066e..6b45b14 100644
--- a/test/keystrokes/gtk-demo/role_push_button.py
+++ b/test/keystrokes/gtk-demo/role_push_button.py
@@ -39,12 +39,9 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Button Boxes Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Button Boxes Frame Horizontal Button Boxes Panel Spread Panel OK Button'",
      "     VISIBLE:  'OK Button', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Button Boxes'",
-     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Button Boxes tree level 1'",
      "SPEECH OUTPUT: 'Button Boxes frame'",
-     "SPEECH OUTPUT: 'Horizontal Button Boxes panel Spread panel'",
-     "SPEECH OUTPUT: 'OK button'"]))
+     "SPEECH OUTPUT: 'Horizontal Button Boxes panel Spread panel OK button'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -56,9 +53,7 @@ sequence.append(utils.AssertPresentationAction(
     "OK button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Button Boxes Frame Horizontal Button Boxes Panel Spread Panel OK Button'",
      "     VISIBLE:  'OK Button', cursor=1",
-     "SPEECH OUTPUT: 'OK'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: 'Alt o'"]))
+     "SPEECH OUTPUT: 'OK button Alt o'"]))
 
 ########################################################################
 # Tab to the Cancel button.
@@ -70,7 +65,6 @@ sequence.append(utils.AssertPresentationAction(
     "Cancel button",
     ["BRAILLE LINE:  'gtk-demo Application Button Boxes Frame Horizontal Button Boxes Panel Spread Panel Cancel Button'",
      "     VISIBLE:  'Cancel Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Cancel button'"]))
 
 ########################################################################
@@ -86,8 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "OK Edge button",
     ["BRAILLE LINE:  'gtk-demo Application Button Boxes Frame Horizontal Button Boxes Panel Edge Panel OK Button'",
      "     VISIBLE:  'OK Button', cursor=1",
-     "SPEECH OUTPUT: 'Edge panel'",
-     "SPEECH OUTPUT: 'OK button'"]))
+     "SPEECH OUTPUT: 'Edge panel OK button'"]))
 
 ########################################################################
 # Close the demo
diff --git a/test/keystrokes/gtk-demo/role_radio_button.py b/test/keystrokes/gtk-demo/role_radio_button.py
index 3532b47..ce94f42 100644
--- a/test/keystrokes/gtk-demo/role_radio_button.py
+++ b/test/keystrokes/gtk-demo/role_radio_button.py
@@ -35,8 +35,7 @@ sequence.append(utils.AssertPresentationAction(
     "All Pages radio button",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'All Pages selected radio button'"]))
+     "SPEECH OUTPUT: 'Range All Pages selected radio button'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -48,11 +47,7 @@ sequence.append(utils.AssertPresentationAction(
     "All Pages radio button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y All Pages RadioButton'",
      "     VISIBLE:  '&=y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'All Pages radio button'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'Alt a'"]))
+     "SPEECH OUTPUT: 'Range All Pages radio button selected item 1 of 3 Alt a'"]))
 
 ########################################################################
 # Down arrow to the "Pages:" radio button.
@@ -73,7 +68,6 @@ sequence.append(utils.AssertPresentationAction(
     ["KNOWN ISSUE - the radio button should be presented as selected.",
      "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler & y Pages: RadioButton'",
      "     VISIBLE:  '& y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Pages: not selected radio button'"]))
 
 ########################################################################
@@ -86,11 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     "Range radio button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler &=y Pages: RadioButton'",
      "     VISIBLE:  '&=y Pages: RadioButton', cursor=1",
-     "SPEECH OUTPUT: 'Range'",
-     "SPEECH OUTPUT: 'Pages: radio button'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'item 3 of 3'",
-     "SPEECH OUTPUT: 'Alt e'"]))
+     "SPEECH OUTPUT: 'Range Pages: radio button selected item 3 of 3 Alt e'"]))
 
 ########################################################################
 # Put everything back and close the demo.
@@ -103,7 +93,6 @@ sequence.append(utils.AssertPresentationAction(
     ["KNOWN ISSUE - the radio button should be presented as selected.",
      "BRAILLE LINE:  'gtk-demo Application Print Dialog TabList General Page Range Filler & y All Pages RadioButton'",
      "     VISIBLE:  '& y All Pages RadioButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'All Pages not selected radio button'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_radio_menu_item.py b/test/keystrokes/gtk-demo/role_radio_menu_item.py
index 3208fe9..2ba11ac 100644
--- a/test/keystrokes/gtk-demo/role_radio_menu_item.py
+++ b/test/keystrokes/gtk-demo/role_radio_menu_item.py
@@ -38,7 +38,6 @@ sequence.append(utils.AssertPresentationAction(
     "Red button",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu <x> Red CheckItem(Control r)'",
      "     VISIBLE:  '<x> Red CheckItem(Control r)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Red check item checked Control r'"]))
 
 ########################################################################
@@ -51,13 +50,7 @@ sequence.append(utils.AssertPresentationAction(
     "Red button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu <x> Red CheckItem(Control r)'",
      "     VISIBLE:  '<x> Red CheckItem(Control r)', cursor=1",
-     "SPEECH OUTPUT: 'Color menu'",
-     "SPEECH OUTPUT: 'Red'",
-     "SPEECH OUTPUT: 'check item'",
-     "SPEECH OUTPUT: 'checked'",
-     "SPEECH OUTPUT: 'Control r'",
-     "SPEECH OUTPUT: 'item 1 of 3'",
-     "SPEECH OUTPUT: 'r'"]))
+     "SPEECH OUTPUT: 'Color menu Red check item checked Control r item 1 of 3 r'"]))
 
 ########################################################################
 # Down arrow to the "Green" menu item.
@@ -70,7 +63,6 @@ sequence.append(utils.AssertPresentationAction(
     "Green button",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu < > Green CheckItem(Control g)'",
      "     VISIBLE:  '< > Green CheckItem(Control g)', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Green check item not checked Control g'"]))
 
 ########################################################################
@@ -83,13 +75,7 @@ sequence.append(utils.AssertPresentationAction(
     "Green button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame MenuBar Preferences Menu < > Green CheckItem(Control g)'",
      "     VISIBLE:  '< > Green CheckItem(Control g)', cursor=1",
-     "SPEECH OUTPUT: 'Color menu'",
-     "SPEECH OUTPUT: 'Green'",
-     "SPEECH OUTPUT: 'check item'",
-     "SPEECH OUTPUT: 'not checked'",
-     "SPEECH OUTPUT: 'Control g'",
-     "SPEECH OUTPUT: 'item 2 of 3'",
-     "SPEECH OUTPUT: 'g'"]))
+     "SPEECH OUTPUT: 'Color menu Green check item not checked Control g item 2 of 3 g'"]))
 
 ########################################################################
 # Dismiss the menu and close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_spin_button.py b/test/keystrokes/gtk-demo/role_spin_button.py
index c114a55..67fcc15 100644
--- a/test/keystrokes/gtk-demo/role_spin_button.py
+++ b/test/keystrokes/gtk-demo/role_spin_button.py
@@ -50,7 +50,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Hue: 240 $l', cursor=6",
      "BRAILLE LINE:  'gtk-demo Application Changing color ColorChooser ColorChooser Hue: 240 $l'",
      "     VISIBLE:  'Hue: 240 $l', cursor=9",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Hue: 240 spin button'"]))
 
 ########################################################################
@@ -63,11 +62,7 @@ sequence.append(utils.AssertPresentationAction(
     "Hue spin button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Changing color ColorChooser ColorChooser Hue: 240 $l'",
      "     VISIBLE:  'Hue: 240 $l', cursor=9",
-     "SPEECH OUTPUT: 'Hue:'",
-     "SPEECH OUTPUT: 'spin button'",
-     "SPEECH OUTPUT: '240'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'Alt h'"]))
+     "SPEECH OUTPUT: 'Hue: spin button 240 selected Alt h'"]))
 
 ########################################################################
 # Do an extended "Where Am I" via double KP_Enter.
@@ -82,16 +77,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Hue: 240 $l', cursor=9",
      "BRAILLE LINE:  'gtk-demo Application Changing color ColorChooser ColorChooser Hue: 240 $l'",
      "     VISIBLE:  'Hue: 240 $l', cursor=9",
-     "SPEECH OUTPUT: 'Hue:'",
-     "SPEECH OUTPUT: 'spin button'",
-     "SPEECH OUTPUT: '240'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'Alt h'",
-     "SPEECH OUTPUT: 'Hue:'",
-     "SPEECH OUTPUT: 'spin button'",
-     "SPEECH OUTPUT: '240'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: 'Alt h'"]))
+     "SPEECH OUTPUT: 'Hue: spin button 240 selected Alt h'",
+     "SPEECH OUTPUT: 'Hue: spin button 240 selected Alt h'"]))
 
 ########################################################################
 # Change the value by arrowing down.
@@ -114,7 +101,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'gtk-demo Application Changing color ColorChooser ColorChooser Hue: 240 $l'",
      "     VISIBLE:  'Hue: 240 $l', cursor=6",
      "SPEECH OUTPUT: '240'",
-     "SPEECH OUTPUT: 'unselected'",
      "SPEECH OUTPUT: '240'"]))
 
 ########################################################################
@@ -162,10 +148,7 @@ sequence.append(utils.AssertPresentationAction(
     "Hue spin button caret navigation",
     ["BRAILLE LINE:  'gtk-demo Application Changing color ColorChooser ColorChooser Hue: 240 $l'",
      "     VISIBLE:  'Hue: 240 $l', cursor=7",
-     "SPEECH OUTPUT: 'Hue:'",
-     "SPEECH OUTPUT: 'spin button'",
-     "SPEECH OUTPUT: '240'",
-     "SPEECH OUTPUT: 'Alt h'"]))
+     "SPEECH OUTPUT: 'Hue: spin button 240 Alt h'"]))
 
 ########################################################################
 # Close the Color Chooser dialog
diff --git a/test/keystrokes/gtk-demo/role_split_pane.py b/test/keystrokes/gtk-demo/role_split_pane.py
index 0b99596..0ea61c5 100644
--- a/test/keystrokes/gtk-demo/role_split_pane.py
+++ b/test/keystrokes/gtk-demo/role_split_pane.py
@@ -35,7 +35,6 @@ sequence.append(utils.AssertPresentationAction(
     "Split pane",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame 60 SplitPane'",
      "     VISIBLE:  '60 SplitPane', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'split pane 60'"]))
 
 ########################################################################
@@ -64,9 +63,7 @@ sequence.append(utils.AssertPresentationAction(
     "Split pane Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Panes Frame 61 SplitPane'",
      "     VISIBLE:  '61 SplitPane', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'split pane'",
-     "SPEECH OUTPUT: '61'"]))
+     "SPEECH OUTPUT: 'split pane 61'"]))
 
 ########################################################################
 # Put things back the way they were
diff --git a/test/keystrokes/gtk-demo/role_table.py b/test/keystrokes/gtk-demo/role_table.py
index 8ff62cd..e74fba8 100644
--- a/test/keystrokes/gtk-demo/role_table.py
+++ b/test/keystrokes/gtk-demo/role_table.py
@@ -61,19 +61,16 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Shopping list Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 3 bottles of coke[ ]*'",
      "     VISIBLE:  '3 bottles of coke[ ]*', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Editable Cells'",
-     "SPEECH OUTPUT: 'tree level 2'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Editable Cells tree level 2'",
      "SPEECH OUTPUT: 'Shopping list frame'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Number column header'",
-     "SPEECH OUTPUT: '3 bottles of coke[ ]*'"])) # [WDW - the [ ]* re is to account for the last
-                                                 # column not showing on some systems (e.g.,
-                                                 # Ubuntu, but showing on others (e.g., Solaris).
-                                                 # When the last column is showing, the speech
-                                                 # generator will join a ' ' to the end.]
-                                                 # We will add this regular expression to the
-                                                 # rest of the tests as well.
+     "SPEECH OUTPUT: 'Number column header 3 bottles of coke blank'"]))
+     # [WDW - the [ ]* re is to account for the last
+     # column not showing on some systems (e.g.,
+     # Ubuntu, but showing on others (e.g., Solaris).
+     # When the last column is showing, the speech
+     # generator will join a ' ' to the end.]
+     # We will add this regular expression to the
+     # rest of the tests as well.
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -85,12 +82,8 @@ sequence.append(utils.AssertPresentationAction(
     "Table Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 3 bottles of coke[ ]*'",
      "     VISIBLE:  '3 bottles of coke[ ]*', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Number'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: '3'",
-     "SPEECH OUTPUT: 'column 1 of 3'",
-     "SPEECH OUTPUT: 'row 1 of 5'"]))
+     "SPEECH OUTPUT: 'table Number cell 3'",
+     "SPEECH OUTPUT: 'column 1 of 3 row 1 of 5'"]))
 
 ########################################################################
 # Down arrow to the next line.
@@ -106,8 +99,7 @@ sequence.append(utils.AssertPresentationAction(
     "Table down one line",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 5 packages of noodles[ ]*'",
      "     VISIBLE:  '5 packages of noodles[ ]*', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: '5 packages of noodles[ ]*'"]))
+     "SPEECH OUTPUT: '5 packages of noodles blank'"]))
 
 ########################################################################
 # Do a basic "Where Am I" via KP_Enter.
@@ -118,12 +110,8 @@ sequence.append(utils.AssertPresentationAction(
     "Table Where Am I (again)",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Number ColumnHeader 5'",
      "     VISIBLE:  '5', cursor=1",
-     "SPEECH OUTPUT: 'table'",
-     "SPEECH OUTPUT: 'Number'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: '5'",
-     "SPEECH OUTPUT: 'column 1 of 3'",
-     "SPEECH OUTPUT: 'row 2 of 5'"]))
+     "SPEECH OUTPUT: 'table Number cell 5'",
+     "SPEECH OUTPUT: 'column 1 of 3 row 2 of 5'"]))
 
 ########################################################################
 # Turn reading of rows off.
@@ -151,9 +139,7 @@ sequence.append(utils.AssertPresentationAction(
     "Table up to packages of noodles",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Product ColumnHeader packages of noodles Cell'",
      "     VISIBLE:  'packages of noodles Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Product column header'",
-     "SPEECH OUTPUT: 'packages of noodles'"]))
+     "SPEECH OUTPUT: 'Product column header packages of noodles'"]))
 
 sequence.append(utils.StartRecordingAction())
 sequence.append(KeyComboAction("Up", 500))
@@ -166,7 +152,6 @@ sequence.append(utils.AssertPresentationAction(
     "Table up to bottles of coke",
     ["BRAILLE LINE:  'gtk-demo Application Shopping list Frame ScrollPane Table Product ColumnHeader bottles of coke Cell'",
      "     VISIBLE:  'bottles of coke Cell', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'bottles of coke'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_tear_off_menu_item.py b/test/keystrokes/gtk-demo/role_tear_off_menu_item.py
index 9083665..35e54db 100644
--- a/test/keystrokes/gtk-demo/role_tear_off_menu_item.py
+++ b/test/keystrokes/gtk-demo/role_tear_off_menu_item.py
@@ -42,7 +42,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tear off menu item",
     ["BRAILLE LINE:  'gtk-demo Application menus Frame MenuBar TearOffMenuItem'",
      "     VISIBLE:  'TearOffMenuItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'tear off menu item'"]))
 
 ########################################################################
@@ -55,7 +54,6 @@ sequence.append(utils.AssertPresentationAction(
     "Tear off menu item Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application menus Frame MenuBar TearOffMenuItem'",
      "     VISIBLE:  'TearOffMenuItem', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'tear off menu item'"]))
 
 ########################################################################
diff --git a/test/keystrokes/gtk-demo/role_text_multiline.py b/test/keystrokes/gtk-demo/role_text_multiline.py
index f9c25b9..ab20a11 100644
--- a/test/keystrokes/gtk-demo/role_text_multiline.py
+++ b/test/keystrokes/gtk-demo/role_text_multiline.py
@@ -230,11 +230,8 @@ sequence.append(utils.AssertPresentationAction(
     "Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ScrollPane This is a test. $l'",
      "     VISIBLE:  'This is a test. $l', cursor=11",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: ' is a '",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'text  is a '",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ########################################################################
 # Press Home to move to the beginning of the line. Arrow down to 
@@ -310,11 +307,8 @@ sequence.append(utils.AssertPresentationAction(
     "Basic Where Am I multiline selection",
     ["BRAILLE LINE:  'The keyboard sure can get sticky. $l'",
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'The keyboard'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'text The keyboard'",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter 2x.
@@ -329,17 +323,11 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
      "BRAILLE LINE:  'The keyboard sure can get sticky. $l'",
      "     VISIBLE:  'The keyboard sure can get sticky', cursor=13",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'The keyboard'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'text'",
-     "SPEECH OUTPUT: 'I'm just typing away like a mad little monkey with nothing better to do in my life than eat fruit and type.",
+     "SPEECH OUTPUT: 'text The keyboard'",
+     "SPEECH OUTPUT: 'selected '",
+     "SPEECH OUTPUT: 'text I'm just typing away like a mad little monkey with nothing better to do in my life than eat fruit and type.",
      "The keyboard'",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'selected '"]))
 
 ########################################################################
 # Try a "SayAll".
diff --git a/test/keystrokes/gtk-demo/role_toggle_button.py b/test/keystrokes/gtk-demo/role_toggle_button.py
index 19e7762..0e8045a 100644
--- a/test/keystrokes/gtk-demo/role_toggle_button.py
+++ b/test/keystrokes/gtk-demo/role_toggle_button.py
@@ -39,11 +39,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'GtkExpander Dialog', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application GtkExpander Dialog & y Details ToggleButton'",
      "     VISIBLE:  '& y Details ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Expander'",
-     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Expander tree level 1'",
      "SPEECH OUTPUT: 'GtkExpander Expander demo. Click on the triangle for details.'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Details toggle button not pressed'"]))
 
 ########################################################################
@@ -56,9 +53,7 @@ sequence.append(utils.AssertPresentationAction(
     "Toggle button Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkExpander Dialog & y Details ToggleButton'",
      "     VISIBLE:  '& y Details ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'Details'",
-     "SPEECH OUTPUT: 'toggle button'",
-     "SPEECH OUTPUT: 'not pressed'"]))
+     "SPEECH OUTPUT: 'Details toggle button not pressed'"]))
 
 ########################################################################
 # Toggle the state of the "Details" button.
@@ -86,9 +81,7 @@ sequence.append(utils.AssertPresentationAction(
     "Toggle button pressed Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application GtkExpander Dialog &=y Details ToggleButton'",
      "     VISIBLE:  '&=y Details ToggleButton', cursor=1",
-     "SPEECH OUTPUT: 'Details'",
-     "SPEECH OUTPUT: 'toggle button'",
-     "SPEECH OUTPUT: 'pressed'"]))
+     "SPEECH OUTPUT: 'Details toggle button pressed'"]))
 
 ########################################################################
 # Toggle the state of the "Details" button.
diff --git a/test/keystrokes/gtk-demo/role_toolbar.py b/test/keystrokes/gtk-demo/role_toolbar.py
index 7cd3d9b..c244954 100644
--- a/test/keystrokes/gtk-demo/role_toolbar.py
+++ b/test/keystrokes/gtk-demo/role_toolbar.py
@@ -40,11 +40,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Application Window Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Open Button'",
      "     VISIBLE:  'Open Button', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Application main window'",
-     "SPEECH OUTPUT: 'tree level 1'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Application main window tree level 1'",
      "SPEECH OUTPUT: 'Application Window frame'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Open button'"]))
 
 ########################################################################
@@ -58,9 +55,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Open Button'",
      "     VISIBLE:  'Open Button', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Open'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Open button '"]))
 
 ########################################################################
 # Arrow Right to the triangular button next to the "Open" button.
@@ -72,7 +67,6 @@ sequence.append(utils.AssertPresentationAction(
     "Open triangle toggle button",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar & y ToggleButton'",
      "     VISIBLE:  '& y ToggleButton', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'toggle button not pressed'"]))
 
 ########################################################################
@@ -86,9 +80,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar & y ToggleButton'",
      "     VISIBLE:  '& y ToggleButton', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'toggle button'",
-     "SPEECH OUTPUT: 'not pressed'"]))
+     "SPEECH OUTPUT: 'toggle button not pressed'"]))
 
 ########################################################################
 # Arrow Right to the the "Quit" button.
@@ -100,7 +92,6 @@ sequence.append(utils.AssertPresentationAction(
     "Quit button",
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Quit Button'",
      "     VISIBLE:  'Quit Button', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Quit button'"]))
 
 ########################################################################
@@ -114,9 +105,7 @@ sequence.append(utils.AssertPresentationAction(
     ["BRAILLE LINE:  'gtk-demo Application Application Window Frame ToolBar Quit Button'",
      "     VISIBLE:  'Quit Button', cursor=1",
      "SPEECH OUTPUT: 'tool bar'",
-     "SPEECH OUTPUT: 'Quit'",
-     "SPEECH OUTPUT: 'button'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'Quit button '"]))
 
 ########################################################################
 # Close the Application Window demo window
diff --git a/test/keystrokes/gtk-demo/role_tree_table.py b/test/keystrokes/gtk-demo/role_tree_table.py
index 74606e5..4a971b3 100644
--- a/test/keystrokes/gtk-demo/role_tree_table.py
+++ b/test/keystrokes/gtk-demo/role_tree_table.py
@@ -52,11 +52,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Card planning sheet Frame', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader'",
      "     VISIBLE:  'Holiday ColumnHeader', cursor=1",
-     "SPEECH OUTPUT: 'Widget (double click for demo) column header'",
-     "SPEECH OUTPUT: 'Tree Store'",
-     "SPEECH OUTPUT: 'tree level 2'",
+     "SPEECH OUTPUT: 'Widget (double click for demo) page Widget (double click for demo) column header Tree Store tree level 2'",
      "SPEECH OUTPUT: 'Card planning sheet frame'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Holiday column header'"]))
 
 ########################################################################
@@ -85,14 +82,9 @@ sequence.append(utils.AssertPresentationAction(
     "January cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 53'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
+     "SPEECH OUTPUT: 'expanded tree level 1'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -107,28 +99,13 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January expanded < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January expanded < > Alex < > Ha', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 53'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 53'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'expanded'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
+     "SPEECH OUTPUT: 'expanded tree level 1'",
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 53'",
+     "SPEECH OUTPUT: 'January check box not checked check box not checked check box not checked check box not checked check box not checked'",
+     "SPEECH OUTPUT: 'expanded tree level 1'"]))
 
 ########################################################################
 # Collapse the cell.
@@ -156,14 +133,9 @@ sequence.append(utils.AssertPresentationAction(
     "January cell collapsed basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 50'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
+     "SPEECH OUTPUT: 'collapsed tree level 1'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -178,28 +150,13 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader January collapsed < > Alex < > Havoc < > Tim < > Owen < > Dave TREE LEVEL 1'",
      "     VISIBLE:  'January collapsed < > Alex < > H', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 50'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Holiday'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'column 1 of 6'",
-     "SPEECH OUTPUT: 'row 1 of 50'",
-     "SPEECH OUTPUT: 'January'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'check box not checked'",
-     "SPEECH OUTPUT: 'collapsed'",
-     "SPEECH OUTPUT: 'tree level 1'"]))
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
+     "SPEECH OUTPUT: 'collapsed tree level 1'",
+     "SPEECH OUTPUT: 'tree table Holiday cell January'",
+     "SPEECH OUTPUT: 'column 1 of 6 row 1 of 50'",
+     "SPEECH OUTPUT: 'January check box not checked check box not checked check box not checked check box not checked check box not checked'",
+     "SPEECH OUTPUT: 'collapsed tree level 1'"]))
 
 ########################################################################
 # Expand the cell again.
@@ -231,9 +188,7 @@ sequence.append(utils.AssertPresentationAction(
     "New Year's Day cell",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Holiday ColumnHeader New Years Day <x> Alex <x> Havoc <x> Tim <x> Owen < > Dave TREE LEVEL 2'",
      "     VISIBLE:  'New Years Day <x> Alex <x> Havoc', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'New Years Day Alex check box checked  Havoc check box checked  Tim check box checked  Owen check box checked  Dave check box not checked '",
-     "SPEECH OUTPUT: 'tree level 2'"]))
+     "SPEECH OUTPUT: 'New Years Day Alex check box checked Havoc check box checked Tim check box checked Owen check box checked Dave check box not checked tree level 2'"]))
 
 ########################################################################
 # Arrow right to a column.
@@ -249,9 +204,7 @@ sequence.append(utils.AssertPresentationAction(
     "Alex checkbox cell",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader New Years Day <x> Alex <x> Havoc <x> Tim <x> Owen < > Dave'",
      "     VISIBLE:  '<x> Alex <x> Havoc <x> Tim <x> O', cursor=1",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'Alex column header'",
-     "SPEECH OUTPUT: 'New Years Day Alex check box checked  Havoc check box checked  Tim check box checked  Owen check box checked  Dave check box not checked '"]))
+     "SPEECH OUTPUT: 'Alex column header check box checked'"]))
 
 #
 # [[[BUG?: Somewhere around here, the demo flakes out.]]]
@@ -267,12 +220,8 @@ sequence.append(utils.AssertPresentationAction(
     "Alex checkbox cell basic Where Am I",
     ["BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
      "     VISIBLE:  '<x> Alex', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Alex'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6'",
-     "SPEECH OUTPUT: 'row 2 of 53'"]))
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
+     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'"]))
 
 ########################################################################
 # Do a detailed "Where Am I" via KP_Enter.
@@ -287,24 +236,11 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  '<x> Alex', cursor=1",
      "BRAILLE LINE:  'gtk-demo Application Card planning sheet Frame ScrollPane TreeTable Alex ColumnHeader <x> Alex'",
      "     VISIBLE:  '<x> Alex', cursor=1",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Alex'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6'",
-     "SPEECH OUTPUT: 'row 2 of 53'",
-     "SPEECH OUTPUT: 'tree table'",
-     "SPEECH OUTPUT: 'Alex'",
-     "SPEECH OUTPUT: 'cell'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'column 2 of 6'",
-     "SPEECH OUTPUT: 'row 2 of 53'",
-     "SPEECH OUTPUT: 'New Years Day'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'check box checked'",
-     "SPEECH OUTPUT: 'check box not checked'"]))
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
+     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'",
+     "SPEECH OUTPUT: 'tree table Alex cell check box checked'",
+     "SPEECH OUTPUT: 'column 2 of 6 row 2 of 53'",
+     "SPEECH OUTPUT: 'New Years Day check box checked check box checked check box checked check box checked check box not checked'"]))
 
 ########################################################################
 # Change the state of the checkbox.
diff --git a/test/keystrokes/oowriter/bug_350219.py b/test/keystrokes/oowriter/bug_350219.py
index 02c2d93..8c4ae6d 100644
--- a/test/keystrokes/oowriter/bug_350219.py
+++ b/test/keystrokes/oowriter/bug_350219.py
@@ -36,8 +36,7 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'soffice Application Untitled[ ]*2 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*2 - " + utils.getOOoName("Writer") + " RootPane ScrollPane Document view  \$l'",
      "     VISIBLE:  ' $l', cursor=1",
      "SPEECH OUTPUT: 'Untitled[ ]*2 - " + utils.getOOoName("Writer") + " frame'",
-     "SPEECH OUTPUT: 'blank'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'blank'"]))
 
 ######################################################################
 # 3. Enter Alt-f, Alt-c to close the Writer application.
diff --git a/test/keystrokes/oowriter/bug_361747.py b/test/keystrokes/oowriter/bug_361747.py
index 36d00c5..72750e7 100644
--- a/test/keystrokes/oowriter/bug_361747.py
+++ b/test/keystrokes/oowriter/bug_361747.py
@@ -59,7 +59,8 @@ sequence.append(utils.AssertPresentationAction(
     "Text information for bold word",
     ["SPEECH OUTPUT: 'size 12'",
      "SPEECH OUTPUT: 'family name FreeSerif'",
-     "SPEECH OUTPUT: 'bold'"]))
+     "SPEECH OUTPUT: 'bold'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 7. Type Control-right and Insert-f to get the text information
@@ -77,7 +78,8 @@ sequence.append(utils.AssertPresentationAction(
      "SPEECH OUTPUT: 'Italic '",
      "SPEECH OUTPUT: 'size 12'",
      "SPEECH OUTPUT: 'family name FreeSerif'",
-     "SPEECH OUTPUT: 'style italic'"]))
+     "SPEECH OUTPUT: 'style italic'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 8. Type Control-right and Insert-f to get the text information
@@ -94,7 +96,8 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Bold Italic Normal $l', cursor=13",
      "SPEECH OUTPUT: 'Normal'",
      "SPEECH OUTPUT: 'size 12'",
-     "SPEECH OUTPUT: 'family name FreeSerif'"]))
+     "SPEECH OUTPUT: 'family name FreeSerif'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 9. Enter Alt-f, Alt-c to close the Writer application.
diff --git a/test/keystrokes/oowriter/bug_364765.py b/test/keystrokes/oowriter/bug_364765.py
index fcdf664..e7214e3 100644
--- a/test/keystrokes/oowriter/bug_364765.py
+++ b/test/keystrokes/oowriter/bug_364765.py
@@ -32,8 +32,7 @@ sequence.append(utils.AssertPresentationAction(
     "Press W to open the Wizards submenu",
     ["BRAILLE LINE:  'soffice Application Untitled[ ]*1 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*1 - " + utils.getOOoName("Writer") + " RootPane MenuBar File Menu Letter...'",
      "     VISIBLE:  'Letter...', cursor=1",
-     "SPEECH OUTPUT: 'Wizards menu'",
-     "SPEECH OUTPUT: 'Letter...'"]))
+     "SPEECH OUTPUT: 'Wizards menu Letter...'"]))
 
 ######################################################################
 # 4. Press Escape to close the Wizards submenu.
@@ -45,7 +44,6 @@ sequence.append(utils.AssertPresentationAction(
     "Press Escape to close the Wizards submenu",
     ["BRAILLE LINE:  'soffice Application Untitled[ ]*1 - " + utils.getOOoName("Writer") + " Frame Untitled[ ]*1 - " + utils.getOOoName("Writer") + " RootPane MenuBar Wizards Menu'",
      "     VISIBLE:  'Wizards Menu', cursor=1",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Wizards menu'"]))
 
 ######################################################################
diff --git a/test/keystrokes/oowriter/bug_382408.py b/test/keystrokes/oowriter/bug_382408.py
index 3426b3a..40aad1e 100644
--- a/test/keystrokes/oowriter/bug_382408.py
+++ b/test/keystrokes/oowriter/bug_382408.py
@@ -51,7 +51,7 @@ sequence.append(utils.AssertPresentationAction(
     "Type a down arrow to move to the Mon table column header",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "table-sample(.odt|)", "Calendar-1 Table Sun Mon Tue Wed Thu Fri Sat") + "'",
      "     VISIBLE:  'Mon Tue Wed Thu Fri Sat', cursor=1",
-     "SPEECH OUTPUT: 'table with 7 rows and 7 columns",
+     "SPEECH OUTPUT: 'table with 7 rows and 7 columns.'",
      "SPEECH OUTPUT: 'Sun Mon Tue Wed Thu Fri Sat'"]))
 
 ######################################################################
diff --git a/test/keystrokes/oowriter/bug_384893.py b/test/keystrokes/oowriter/bug_384893.py
index 1280937..281e318 100644
--- a/test/keystrokes/oowriter/bug_384893.py
+++ b/test/keystrokes/oowriter/bug_384893.py
@@ -62,7 +62,8 @@ sequence.append(utils.AssertPresentationAction(
     "Enter Insert-f to get text information on the underlined word",
     ["SPEECH OUTPUT: 'size 12'",
      "SPEECH OUTPUT: 'family name FreeSerif'",
-     "SPEECH OUTPUT: 'underline single'"]))
+     "SPEECH OUTPUT: 'underline single'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 6. Type Control right arrow three times to position the cursor at
@@ -83,7 +84,8 @@ sequence.append(utils.AssertPresentationAction(
     "Enter Insert-f to get text information on the bold word",
     ["SPEECH OUTPUT: 'size 12'",
      "SPEECH OUTPUT: 'family name FreeSerif'",
-     "SPEECH OUTPUT: 'bold'"]))
+     "SPEECH OUTPUT: 'bold'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 8. Enter Alt-f, Alt-c to close the Writer application.
diff --git a/test/keystrokes/oowriter/bug_385828.py b/test/keystrokes/oowriter/bug_385828.py
index b9f5ece..f7c068d 100644
--- a/test/keystrokes/oowriter/bug_385828.py
+++ b/test/keystrokes/oowriter/bug_385828.py
@@ -36,15 +36,14 @@ sequence.append(WaitForWindowActivate("aw-5blue (read-only) - " + utils.getOOoNa
 sequence.append(WaitForFocus("Page design", acc_role=pyatspi.ROLE_LABEL))
 sequence.append(utils.AssertPresentationAction(
     "Press 'a' to bring up the Agenda... wizard",
-    ["BRAILLE LINE:  'soffice Application aw-5blue (read-only) - " + utils.getOOoName("Writer") + " Frame (1 dialog)'",
-     "     VISIBLE:  'aw-5blue \(read-only\) - " + utils.getOOoName("Writer")[0:9] + "', cursor=1",
-     "BRAILLE LINE:  'soffice Application Agenda Wizard Dialog'",
+    ["BRAILLE LINE:  " + utils.getOOoName("Writer") + " Frame (1 dialog)'",
+     "     VISIBLE:  'Frame (1 dialog)', cursor=1",
+     "BRAILLE LINE:  " + utils.getOOoName("Writer") + "'Agenda Wizard Dialog'",
      "     VISIBLE:  'Agenda Wizard Dialog', cursor=1",
-     "BRAILLE LINE:  'soffice Application Agenda Wizard Dialog Agenda Wizard OptionPane Steps Panel  $l'",
+     "BRAILLE LINE:  " + utils.getOOoName("Writer") + "'Agenda Wizard Dialog Agenda Wizard OptionPane Steps Panel  $l'",
      "     VISIBLE:  '  $l', cursor=1",
-     "SPEECH OUTPUT: 'aw-5blue (read-only) - " + utils.getOOoName("Writer") + " frame 1 unfocused dialog'",
+     "SPEECH OUTPUT: 'frame 1 unfocused dialog'",
      "SPEECH OUTPUT: 'Agenda Wizard Please choose the page design for the agenda 1. Page design 2. General information 3. Headings to include 4. Names 5. Agenda items 6. Name and location'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Page design label'"]))
 
 ######################################################################
diff --git a/test/keystrokes/oowriter/bug_413909.py b/test/keystrokes/oowriter/bug_413909.py
index 7424f74..1c9bc91 100644
--- a/test/keystrokes/oowriter/bug_413909.py
+++ b/test/keystrokes/oowriter/bug_413909.py
@@ -101,7 +101,6 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Change Button', cursor=1",
      "SPEECH OUTPUT: 'Spell(ing|check): [ \(]*English \(USA\)[\)]*'",
      "SPEECH OUTPUT: 'Misspelled word: quuuiick Context is The quuuiick brown fox'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'Change button'"]))
 
 ######################################################################
diff --git a/test/keystrokes/oowriter/bug_435201.py b/test/keystrokes/oowriter/bug_435201.py
index 6bb784a..72dc740 100644
--- a/test/keystrokes/oowriter/bug_435201.py
+++ b/test/keystrokes/oowriter/bug_435201.py
@@ -49,8 +49,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  ' \$l', cursor=1",
      "BRAILLE LINE:  ' \$l'",
      "     VISIBLE:  ' \$l', cursor=1",
-     "SPEECH OUTPUT: 'blank'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'blank'"]))
 
 ######################################################################
 # 5. Type Control-down to move to the next paragraph.
@@ -78,8 +77,7 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  ' \$l', cursor=1",
      "BRAILLE LINE:  ' \$l'",
      "     VISIBLE:  ' \$l', cursor=1",
-     "SPEECH OUTPUT: 'blank'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'blank'"]))
 
 ######################################################################
 # 7. Type Control-down to move to the next paragraph.
diff --git a/test/keystrokes/oowriter/bug_435226.py b/test/keystrokes/oowriter/bug_435226.py
index 4375a29..67bf1e3 100644
--- a/test/keystrokes/oowriter/bug_435226.py
+++ b/test/keystrokes/oowriter/bug_435226.py
@@ -74,11 +74,8 @@ sequence.append(utils.AssertPresentationAction(
     "Type KP-Enter once to do a 'single-click' where-am-I operation",
     ["BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l") + "'",
      "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=17",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'paragraph'",
-     "SPEECH OUTPUT: 'Hm! She is made '",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'paragraph Hm! She is made '",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ######################################################################
 # 8. Type KP-Enter twice to do a "double-click" where-am-I operation.
@@ -93,16 +90,10 @@ sequence.append(utils.AssertPresentationAction(
      "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=17",
      "BRAILLE LINE:  '" + utils.getOOoBrailleLine("Writer", "spanish(.odt|)", "Hm! She is made of harder stuff! Cardinal Fang! Fetch the COMFY CHAIR! \$l") + "'",
      "     VISIBLE:  'Hm! She is made of harder stuff!', cursor=17",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'paragraph'",
-     "SPEECH OUTPUT: 'Hm! She is made '",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: ''",
-     "SPEECH OUTPUT: 'paragraph'",
-     "SPEECH OUTPUT: 'Spanish Inquisition! Our chief weapon is surprise. Surprise and fear. Fear and surprise. Our two weapons are fear and surprise. And ruthless efficiency. Our three weapons are fear, surprise, and ruthless efficiency. And an almost fanatical devotion to the Pope. Our four. No. Amongst our weapons. Amongst our weaponry, are such elements as fear, surprise. I'll come in again. NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse elements as: fear, surprise, ruthless efficiency, an almost fanatical devotion to the Pope, and nice red uniforms - Oh damn! Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall be free. Three last chances. You have three last chances, the nature of which I have divulged in my previous utterance. Hm! She is made '",
-     "SPEECH OUTPUT: 'selected'",
-     "SPEECH OUTPUT: ''"]))
+     "SPEECH OUTPUT: 'paragraph Hm! She is made '",
+     "SPEECH OUTPUT: 'selected '",
+     "SPEECH OUTPUT: 'paragraph Spanish Inquisition! Our chief weapon is surprise. Surprise and fear. Fear and surprise. Our two weapons are fear and surprise. And ruthless efficiency. Our three weapons are fear, surprise, and ruthless efficiency. And an almost fanatical devotion to the Pope. Our four. No. Amongst our weapons. Amongst our weaponry, are such elements as fear, surprise. I'll come in again. NOBODY expects the Spanish Inquisition! Amongst our weaponry are such diverse elements as: fear, surprise, ruthless efficiency, an almost fanatical devotion to the Pope, and nice red uniforms - Oh damn! Now old lady, you have one last chance. Confess the heinous sin of heresy, reject the works of the ungodly. Two last chances. And you shall be free. Three last chances. You have three last chances, the nature of which I have divulged in my previous utterance. Hm! She is made  ;  paragraph style Preformatted Text'",
+     "SPEECH OUTPUT: 'selected '"]))
 
 ######################################################################
 # 9. Enter Alt-f, Alt-c to close the Writer application.
diff --git a/test/keystrokes/oowriter/bug_450210.py b/test/keystrokes/oowriter/bug_450210.py
index a8659a6..76aa86e 100644
--- a/test/keystrokes/oowriter/bug_450210.py
+++ b/test/keystrokes/oowriter/bug_450210.py
@@ -39,7 +39,6 @@ sequence.append(utils.AssertPresentationAction(
      "BRAILLE LINE:  'soffice Application Open Dialog Open OptionPane File name:  $l'",
      "     VISIBLE:  'File name:  $l', cursor=12",
      "SPEECH OUTPUT: 'Open'",
-     "SPEECH OUTPUT: ''",
      "SPEECH OUTPUT: 'File name: text '"]))
 
 ######################################################################
diff --git a/test/keystrokes/oowriter/bug_469367.py b/test/keystrokes/oowriter/bug_469367.py
index f692e87..173bd7b 100644
--- a/test/keystrokes/oowriter/bug_469367.py
+++ b/test/keystrokes/oowriter/bug_469367.py
@@ -57,7 +57,8 @@ sequence.append(KeyReleaseAction(0, None, "KP_Insert"))
 sequence.append(utils.AssertPresentationAction(
     "Enter Insert-f to get text information",
     ["SPEECH OUTPUT: 'size 12'",
-     "SPEECH OUTPUT: 'family name FreeSerif'"]))
+     "SPEECH OUTPUT: 'family name FreeSerif'",
+     "SPEECH OUTPUT: 'paragraph style Default'"]))
 
 ######################################################################
 # 6. Enter Alt-f, Alt-c to close the Writer application.
diff --git a/test/keystrokes/oowriter/table-sample.odt b/test/keystrokes/oowriter/table-sample.odt
index 6baabed..589daf4 100644
Binary files a/test/keystrokes/oowriter/table-sample.odt and b/test/keystrokes/oowriter/table-sample.odt differ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]