Index: src/orca/scripts/apps/evolution/script.py
===================================================================
--- src/orca/scripts/apps/evolution/script.py	(revision 3893)
+++ src/orca/scripts/apps/evolution/script.py	(working copy)
@@ -38,7 +38,6 @@
 import orca.speech as speech
 import orca.speechserver as speechserver
 import orca.settings as settings
-import orca.chnames as chnames
 
 from orca.orca_i18n import _ # for gettext support
 
@@ -97,7 +96,7 @@
 
         # Pylint is confused and flags several errors of the type:
         #
-        # E1101:282:Script.__init__: Module 'orca.rolenames' has no 
+        # E1101:282:Script.__init__: Module 'orca.rolenames' has no
         # 'ROLE_CALENDAR_VIEW' member
         #
         # So for now, we just disable these errors in this method.
@@ -460,7 +459,7 @@
                 done = True
 
         # If there is anything left unspoken, speak it now.
-        # 
+        #
         if len(string) != 0:
             string = self.adjustForRepeats(string)
             if string.isupper():
@@ -526,7 +525,7 @@
         line = self.adjustForRepeats(string)
 
         if self.speakNewLine(obj):
-            speech.speak(chnames.getCharacterName("\n"), None, False)
+            speech.speakCharacter("\n", None)
 
         if self.speakBlankLine(obj):
             # Translators: "blank" is a short word to mean the
@@ -591,7 +590,7 @@
         brailleGen = self.brailleGenerator
         speechGen = self.speechGenerator
 
-        # Save the previous role hierarchy list for possible comparison 
+        # Save the previous role hierarchy list for possible comparison
         # in section 8).
         #
         self.lastRolesList = self.rolesList
@@ -631,7 +630,6 @@
             self.presentMessageLine(event.source, newLocusOfFocus)
             return
 
-
         # 2) Mail view: current message pane: "standard" mail header lines.
         #
         # Check if the focus is in the From:, To:, Subject: or Date: headers
@@ -727,7 +725,7 @@
                 parentTable.getColumnAtIndex(event.source.getIndexInParent())
 
             # If we are on the same row, then just speak/braille the table
-            # cell as if settings.readTableCellRow was False. 
+            # cell as if settings.readTableCellRow was False.
             # See bug #503874 for more details.
             #
             if self.lastMessageRow == row:
@@ -740,7 +738,7 @@
             # cells (the user has moved focus up or down the list, or just
             # deleted a message), or just the current one (focus has moved
             # left or right in the same row). If we at the start or the end
-            # of the message header list and the row and column haven't 
+            # of the message header list and the row and column haven't
             # changed, then speak all the table cells.
             #
             justDeleted = False
@@ -1186,9 +1184,9 @@
             # We are getting extra (bogus?) "focus:" events from Evolution
             # when we type the first character at the beginning of a line.
             # If the last input event was a keyboard event and the parent
-            # of the locusOfFocus and the event.source are the same, and 
+            # of the locusOfFocus and the event.source are the same, and
             # the last roles hierarchy is the same as this one and
-            # the last key pressed wasn't a navigation key, then just 
+            # the last key pressed wasn't a navigation key, then just
             # ignore it. See bug #490317 for more details.
             #
             if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
@@ -1413,7 +1411,7 @@
         line = text.getTextAtOffset(caretOffset, \
             pyatspi.TEXT_BOUNDARY_LINE_START)
 
-        debug.println(debug.LEVEL_FINEST, 
+        debug.println(debug.LEVEL_FINEST,
             "speakBlankLine: start=%d, end=%d, line=<%s>" % \
             (line[1], line[2], line[0]))
 
@@ -1424,7 +1422,6 @@
         else:
             return False
 
-
     def onStateChanged(self, event):
         """Called whenever an object's state changes.  We are only
         interested in "object:state-changed:showing" events for any
@@ -1479,7 +1476,7 @@
         default.Script.onStateChanged(self, event)
 
     def onFocus(self, event):
-        """Called whenever an object gets focus.  
+        """Called whenever an object gets focus.
 
         Arguments:
         - event: the Event
@@ -1489,9 +1486,9 @@
         # two focus events:  One for the index of the new message prior to
         # deletion and one for the index of the new message after deletion.
         # This causes us to speak the message after the one that gets focus
-        # prior to speaking the actual message that gets focus. 
+        # prior to speaking the actual message that gets focus.
         # See bug #347964.
-        # 
+        #
         if isinstance(orca_state.lastInputEvent,
                       input_event.KeyboardEvent):
             string = orca_state.lastNonModifierKeyEvent.event_string
Index: src/orca/scripts/apps/gnome-terminal.py
===================================================================
--- src/orca/scripts/apps/gnome-terminal.py	(revision 3893)
+++ src/orca/scripts/apps/gnome-terminal.py	(working copy)
@@ -156,10 +156,15 @@
         #
         character = event.any_data.decode("UTF-8")[0].encode("UTF-8")
         if character.isupper():
-            speech.speak(character, self.voices[settings.UPPERCASE_VOICE])
+            voice = self.voices[settings.UPPERCASE_VOICE]
         else:
-            speech.speak(character)
+            voice = self.voices[settings.DEFAULT_VOICE]
 
+        if len(character.decode('utf-8')) == 1:
+            speech.speakCharacter(character, voice)
+        else:
+            speech.speak(character, voice, False)
+
     def onTextInserted(self, event):
         """Called whenever text is inserted into an object.
 
Index: src/orca/scripts/apps/gcalctool/script.py
===================================================================
--- src/orca/scripts/apps/gcalctool/script.py	(revision 3893)
+++ src/orca/scripts/apps/gcalctool/script.py	(working copy)
@@ -35,6 +35,8 @@
 from speech_generator import SpeechGenerator
 from where_am_i import WhereAmI
 
+from orca.orca_i18n import _ # for gettext support
+
 ########################################################################
 #                                                                      #
 # The GCalcTool script class.                                          #
@@ -99,7 +101,11 @@
             # gcalctool display. Inform the user.
             #
             if len(d) == 0:
-                contents = "Unable to get calculator display"
+                # Translators: this is an indication that Orca is unable to
+                # obtain the display of the gcalctool calculator, which is
+                # the area where calculation results are presented.
+                #
+                contents = _("Unable to get calculator display")
                 speech.speak(contents)
                 braille.displayMessage(contents)
             else:
Index: src/orca/scripts/apps/acroread.py
===================================================================
--- src/orca/scripts/apps/acroread.py	(revision 3893)
+++ src/orca/scripts/apps/acroread.py	(working copy)
@@ -22,13 +22,12 @@
 __id__        = "$Id:$"
 __version__   = "$Revision:$"
 __date__      = "$Date:$"
-__copyright__ = "Copyright (c) 2007-2008 Sun Microsystems Inc. and Joanmarie Diggs"
+__copyright__ = "Copyright (c) 2007-2008 Sun Microsystems Inc. Joanmarie Diggs"
 __license__   = "LGPL"
 
 import pyatspi
 
 import orca.braille as braille
-import orca.chnames as chnames
 import orca.debug as debug
 import orca.default as default
 import orca.input_event as input_event
@@ -123,7 +122,7 @@
             self.onStateChanged
         listeners["object:state-changed:focused"]           = \
             self.onStateChanged
-      
+
         return listeners
 
     def getDocument(self, locusOfFocus):
@@ -370,7 +369,7 @@
             if parent and parent.getRole() in [pyatspi.ROLE_DRAWING_AREA,
                                                pyatspi.ROLE_UNKNOWN]:
                 # We're going to get at least one (and likely several)
-                # caret-moved events which will cause this to get spoken, 
+                # caret-moved events which will cause this to get spoken,
                 # so skip it for now.
                 #
                 return
@@ -523,7 +522,7 @@
 
         # [[[TODO: JD - Sometimes it's showing AND we didn't just leave
         # it. This also seems to occur sometimes with the Find toolbar.]]]
-        
+
         self.currentInputEvent = orca_state.lastInputEvent
         self.checkForTableBoundary(orca_state.locusOfFocus, event.source)
         default.Script.onCaretMoved(self, event)
@@ -653,7 +652,7 @@
             if lastKey == "Right":
                 penultimateWord = orca_state.lastWord
                 [lastWord, startOffset, endOffset] = \
-                    text.getTextAtOffset(offset, 
+                    text.getTextAtOffset(offset,
                                          pyatspi.TEXT_BOUNDARY_WORD_START)
                 [word, startOffset, endOffset] = \
                     text.getTextAfterOffset(endOffset+1,
@@ -662,9 +661,7 @@
                     lastCharPW = penultimateWord[len(penultimateWord) - 1]
                     if lastCharPW == "\n":
                         voice = self.voices[settings.DEFAULT_VOICE]
-                        speech.speak(chnames.getCharacterName("\n"),
-                                     voice,
-                                     False)
+                        speech.speakCharacter("\n", voice)
                         if penultimateWord != lastWord:
                             word = lastWord
 
@@ -677,9 +674,7 @@
                     lastChar = word[len(word) - 1]
                     if lastChar == "\n" and lastWord != word:
                         voice = self.voices[settings.DEFAULT_VOICE]
-                        speech.speak(chnames.getCharacterName("\n"),
-                                     voice,
-                                     False)
+                        speech.speakCharacter("\n", voice)
                     if lastWord == word:
                         return
 
Index: src/orca/scripts/apps/soffice/script.py
===================================================================
--- src/orca/scripts/apps/soffice/script.py	(revision 3893)
+++ src/orca/scripts/apps/soffice/script.py	(working copy)
@@ -29,7 +29,6 @@
 import pyatspi
 
 import orca.debug as debug
-import orca.chnames as chnames
 import orca.default as default
 import orca.input_event as input_event
 import orca.braille as braille
@@ -536,7 +535,7 @@
                     found = True
                 current = current.parent
 
-        return found     
+        return found
 
     def isDesiredFocusedItem(self, obj, rolesList):
         """Called to determine if the given object and it's hierarchy of
@@ -564,10 +563,10 @@
 
             if current_role != role:
                 return False
-            
+
             current = self._getParent(current)
 
-        return True   
+        return True
 
     def printHierarchy(self, root, ooi, indent="",
                        onlyShowing=True, omitManaged=True):
@@ -629,14 +628,13 @@
             for frame in app:
                 if frame.childCount < 1 or \
                       frame[0].getRole() not in (pyatspi.ROLE_ROOT_PANE,
-                                                 pyatspi.ROLE_OPTION_PANE): 
+                                                 pyatspi.ROLE_OPTION_PANE):
                     continue
                 root_pane = frame[0]
                 if obj in root_pane:
                     return root_pane
         return parent
 
-
     def checkForTableBoundry(self, oldFocus, newFocus):
         """Check to see if we've entered or left a table.
         When entering a table, announce the table dimensions.
@@ -1061,7 +1059,7 @@
 
     def __isAvailableFieldsPanel(self, event):
         """If we are in the sbase Table Wizard, try to reduce the numerous
-        utterances of "Available fields panel". See bug #465087 for more 
+        utterances of "Available fields panel". See bug #465087 for more
         details.
 
         Arguments:
@@ -1482,7 +1480,6 @@
             #
             default.Script.onWindowActivated(self, event)
 
-
     # This method tries to detect and handle the following cases:
     # 1) Writer: spell checking dialog.
 
@@ -1536,7 +1533,6 @@
 
         default.Script.onNameChanged(self, event)
 
-
     def onFocus(self, event):
         """Called whenever an object gets focus.
 
@@ -1544,7 +1540,7 @@
         - event: the Event
         """
 
-        # If this is a "focus:" event for the Calc Name combo box, catch 
+        # If this is a "focus:" event for the Calc Name combo box, catch
         # it here to reduce verbosity (see bug #364407).
         #
         rolesList = [pyatspi.ROLE_LIST, \
@@ -1606,7 +1602,7 @@
                 if current.getRole() == pyatspi.ROLE_DIALOG and \
                    (current.name and \
                     current.name.startswith(_("Presentation Wizard"))):
-                    self.locusOfFocusChanged(event, None, 
+                    self.locusOfFocusChanged(event, None,
                                              orca_state.locusOfFocus)
                     break
                 current = current.parent
@@ -1729,7 +1725,6 @@
 
         default.Script.onStateChanged(self, event)
 
-
     # This method tries to detect and handle the following cases:
     # 1) Calc: spread sheet Name Box line.
 
@@ -1785,7 +1780,7 @@
                                                  self.inputLineForCell, 0, -1)
                                         if inputLine and (len(inputLine) > 1) \
                                             and (inputLine[0] == "="):
-                                            # Translators: this means a 
+                                            # Translators: this means a
                                             # particular cell in a spreadsheet
                                             # has a formula
                                             # (e.g., "=sum(a1:d1)")
@@ -1928,7 +1923,7 @@
 
         # Speak a newline, if appropriate.
         if self.speakNewLine(event.source):
-            speech.speak(chnames.getCharacterName("\n"), None, False)
+            speech.speakCharacter("\n", None)
 
         # Speak a blank line, if appropriate.
         if self.speakBlankLine(event.source):
@@ -1939,7 +1934,6 @@
 
         default.Script.onCaretMoved(self, event)
 
-
     def speakNewLine(self, obj):
         """Returns True if a newline should be spoken.
            Otherwise, returns False.
@@ -1997,7 +1991,6 @@
 
         return False
 
-
     def speakBlankLine(self, obj):
         """Returns True if a blank line should be spoken.
         Otherwise, returns False.
@@ -2050,9 +2043,9 @@
         - acc: An accessible.
         - offset: Offset in the accessible's text for which to retrieve the
         attributes.
-        - get_defaults: Get the default attributes as well as the unique ones. 
+        - get_defaults: Get the default attributes as well as the unique ones.
         Default is True
-        
+
         Returns a dictionary of attributes, a start offset where the attributes
         begin, and an end offset. Returns ({}, 0, 0) if the accessible does not
         supprt the text attribute.
Index: src/orca/scripts/toolkits/Gecko/script.py
===================================================================
--- src/orca/scripts/toolkits/Gecko/script.py	(revision 3893)
+++ src/orca/scripts/toolkits/Gecko/script.py	(working copy)
@@ -22,10 +22,10 @@
 #
 # E1103:4241:Script.updateBraille: Instance of 'list' has no 'getRole'
 # member (but some types could not be inferred)
-# 
+#
 # I don't know what is going on, so I'm going to tell pylint to
 # disable those messages for Gecko.py.]]]
-# 
+#
 # pylint: disable-msg=E1103
 
 """Custom script for Gecko toolkit.
@@ -68,7 +68,7 @@
 
 from orca.orca_i18n import _
 from orca.orca_i18n import ngettext # for ngettext support
-    
+
 ########################################################################
 #                                                                      #
 # Script                                                               #
@@ -211,7 +211,7 @@
         # are valid.  See bug #471537.
         #
         self._objectForFocusGrab = None
-        
+
         # We don't want to prevent the user from arrowing into an
         # autocomplete when it appears in a search form.  We need to
         # keep track if one has appeared or disappeared.
@@ -239,12 +239,12 @@
         """Returns the "where am I" class for this script.
         """
         return GeckoWhereAmI(self)
-    
+
     def getBookmarks(self):
         """Returns the "bookmarks" class for this script.
         """
         try:
-            return self.bookmarks 
+            return self.bookmarks
         except AttributeError:
             self.bookmarks = GeckoBookmarks(self)
             return self.bookmarks
@@ -521,8 +521,8 @@
             input_event.InputEventHandler(
                 Script.goPreviousLandmark,
                 # Translators: this is for navigating to the previous ARIA
-                # role landmark.  ARIA role landmarks are the W3C defined HTML 
-                # tag attribute 'role' used to identify important part of 
+                # role landmark.  ARIA role landmarks are the W3C defined HTML
+                # tag attribute 'role' used to identify important part of
                 # webpage like banners, main context, search etc.
                 #
                 _("Goes to previous landmark."))
@@ -666,7 +666,7 @@
         self.inputEventHandlers["advanceLivePoliteness"] = \
             input_event.InputEventHandler(
                 Script.advanceLivePoliteness,
-                # Translators: this is for advancing the live regions 
+                # Translators: this is for advancing the live regions
                 # politeness setting
                 #
                 _("Advance live region politeness setting."))
@@ -674,7 +674,7 @@
         self.inputEventHandlers["setLivePolitenessOff"] = \
             input_event.InputEventHandler(
                 Script.setLivePolitenessOff,
-                # Translators: this is for setting all live regions 
+                # Translators: this is for setting all live regions
                 # to 'off' politeness.
                 #
                 _("Set default live region politeness level to off."))
@@ -682,7 +682,7 @@
         self.inputEventHandlers["monitorLiveRegions"] = \
             input_event.InputEventHandler(
                 Script.monitorLiveRegions,
-                # Translators: this is a toggle to monitor live regions 
+                # Translators: this is a toggle to monitor live regions
                 # or not.
                 #
                 _("Monitor live regions."))
@@ -747,8 +747,6 @@
                 # interrupted.
                 #
                 _("Speaks entire document."))
-                
-        
 
     def getListeners(self):
         """Sets up the AT-SPI event listeners for this script.
@@ -1164,7 +1162,7 @@
                  | 1 << pyatspi.MODIFIER_CONTROL),
                 0,
                 self.inputEventHandlers["goLastLiveRegion"]))
-                
+
         # keybindings to provide chat room message history.
         messageKeys = [ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9" ]
         for messageKey in messageKeys:
@@ -1476,7 +1474,7 @@
         self.minimumFindLengthSpinButton = \
                        gtk.SpinButton(self.minimumFindLengthAdjustment, 0.0, 0)
         gtk.Widget.show(self.minimumFindLengthSpinButton)
-        gtk.Box.pack_start(hbox, self.minimumFindLengthSpinButton, 
+        gtk.Box.pack_start(hbox, self.minimumFindLengthSpinButton,
                            False, False, 5)
 
         acc_targets = []
@@ -1701,7 +1699,6 @@
                                                   startOffset, endOffset),
                        voice]
 
-
             obj = contents[-1][0]
             characterOffset = max(0, contents[-1][2] - 1)
 
@@ -1774,7 +1771,7 @@
         displayedText = default.Script.getDisplayedText(self, obj)
         if displayedText \
            and not (obj.getState().contains(pyatspi.STATE_EDITABLE) \
-                    or obj.getRole() in [pyatspi.ROLE_ENTRY, 
+                    or obj.getRole() in [pyatspi.ROLE_ENTRY,
                                          pyatspi.ROLE_PASSWORD_TEXT]):
             displayedText = displayedText.strip()
 
@@ -2082,7 +2079,7 @@
         #
         if isinstance(orca_state.lastInputEvent,
                       input_event.MouseButtonEvent):
-            return                
+            return
 
         default.Script.onCaretMoved(self, event)
 
@@ -2136,7 +2133,7 @@
     def onChildrenChanged(self, event):
         """Called when a child node has changed.  In particular, we are looking
         for addition events often associated with Javascipt insertion.  One such
-        such example would be the programmatic insertion of a tooltip or alert  
+        such example would be the programmatic insertion of a tooltip or alert
         dialog."""
         # no need moving forward if we don't have our target.
         if event.any_data is None:
@@ -2200,7 +2197,7 @@
                                               pyatspi.ROLE_LINK]:
             orca.setLocusOfFocus(event, event.source, False)
             return
-            
+
         # We're going to ignore focus events on the frame.  They
         # are often intermingled with menu activity, wreaking havoc
         # on the context.
@@ -2390,7 +2387,7 @@
             if orca_state.locusOfFocus.getRole() in [pyatspi.ROLE_ENTRY,
                                                      pyatspi.ROLE_LIST_ITEM]:
                 self._autocompleteVisible = event.detail1
-            
+
         # We care when the document frame changes it's busy state.  That
         # means it has started/stopped loading content.
         #
@@ -2501,14 +2498,14 @@
 
             parent_attribs = self._getAttrDictionary(documentFrame.parent)
             parent_tag = parent_attribs.get('tag', '')
-            
+
             if self._loadingDocumentContent or \
                    documentFrame == self._currentFrame or \
                    not parent_tag.endswith('browser'):
                 return
 
             self._currentFrame = documentFrame
-            
+
             braille.displayMessage(documentFrame.name)
             speech.stop()
             speech.speak(
@@ -2531,7 +2528,7 @@
     def handleProgressBarUpdate(self, event, obj):
         """Determine whether this progress bar event should be spoken or not.
         For Firefox, we don't want to speak the small "page load" progress
-        bar. All other Firefox progress bars get passed onto the parent 
+        bar. All other Firefox progress bars get passed onto the parent
         class for handling.
 
         Arguments:
@@ -2727,16 +2724,16 @@
 
         index = self.findObjectOnLine(obj, offset, self.currentLineContents)
         if index < 0:
-            index = self.findObjectOnLine(obj, 
-                                          offset, 
+            index = self.findObjectOnLine(obj,
+                                          offset,
                                           self._previousLineContents)
             if index >= 0:
                 self._nextLineContents = self.currentLineContents
                 self.currentLineContents = self._previousLineContents
                 self._previousLineContents = None
             else:
-                index = self.findObjectOnLine(obj, 
-                                              offset, 
+                index = self.findObjectOnLine(obj,
+                                              offset,
                                               self._nextLineContents)
                 if index >= 0:
                     self._previousLineContents = self.currentLineContents
@@ -2811,7 +2808,7 @@
                 needToRefresh = True
 
         contents = self.currentLineContents
-        index = self.findObjectOnLine(focusedObj, 
+        index = self.findObjectOnLine(focusedObj,
                                       max(0, lineContentsOffset),
                                       contents)
         if index < 0 or needToRefresh:
@@ -2888,8 +2885,8 @@
                                             [pyatspi.ROLE_DOCUMENT_FRAME])
 
                 if not link:
-                    regions = [braille.Text(obj, 
-                                            startOffset=startOffset, 
+                    regions = [braille.Text(obj,
+                                            startOffset=startOffset,
                                             endOffset=endOffset)]
 
                 if link:
@@ -3286,17 +3283,17 @@
                             documentFrame = None
 
         return documentFrame
-                        
+
     def getURI(self, obj):
         """Return the URI for a given link object.
 
         Arguments:
         - obj: the Accessible object.
         """
-        # Getting a link's URI requires a little workaround due to  
+        # Getting a link's URI requires a little workaround due to
         # https://bugzilla.mozilla.org/show_bug.cgi?id=379747.  You should be
         # able to use getURI() directly on the link but instead must use
-        # ihypertext.getLink(0) on parent then use getURI on returned 
+        # ihypertext.getLink(0) on parent then use getURI on returned
         # ihyperlink.
         try:
             ihyperlink = obj.parent.queryHypertext().getLink(0)
@@ -3304,7 +3301,7 @@
             return None
         else:
             return ihyperlink.getURI(0)
-    
+
     def getDocumentFrameURI(self):
         """Returns the URI of the document frame that is active."""
         documentFrame = self.getDocumentFrame()
@@ -3508,7 +3505,7 @@
             return False
 
         # Ideally, we would like to do a inDocumentContent() call to filter out
-        # events that are not in the document.  Unfortunately, this is an 
+        # events that are not in the document.  Unfortunately, this is an
         # expensive call.  Instead we will do some heuristics to filter out
         # chrome events with the least amount of IPC as possible.
 
@@ -3533,8 +3530,8 @@
                     return False
 
                 if attrs.has_key('xml-roles'):
-                    # This eliminates all ARIA widgets that are not 
-                    # considered live        
+                    # This eliminates all ARIA widgets that are not
+                    # considered live
                     if attrs['xml-roles'] != 'alert' \
                                and attrs['xml-roles'] != 'tooltip':
                         return False
@@ -4195,7 +4192,7 @@
         of 0 means there is no heading level."""
 
         level = 0
-        
+
         if obj is None:
             return level
 
@@ -4209,15 +4206,15 @@
                     break
 
         return level
-            
+
     def getNodeLevel(self, obj):
         """ Determines the level of at which this object is at by using the
         object attribute 'level'.  To be consistent with default.getNodeLevel()
         this value is 0-based (Gecko return is 1-based) """
-        
+
         if obj is None or obj.getRole() == pyatspi.ROLE_HEADING:
             return -1
-        
+
         attrs = obj.getAttributes()
         if attrs is None:
             return -1
@@ -4365,7 +4362,7 @@
 
         Arguments
         - obj: the object whose EOCs we need to expand into tuples
-        - offset: the character offset after which 
+        - offset: the character offset after which
         - boundary: the pyatspi text boundary type
 
         Returns a list of object tuples.
@@ -4688,7 +4685,7 @@
                                                       pyatspi.ROLE_LIST,
                                                       pyatspi.ROLE_LIST_ITEM]:
             [nextObj, nextOffset] = self.findNextLine(obj, 0, False)
-            nextLineContents = self.getLineContentsAtOffset(nextObj, 
+            nextLineContents = self.getLineContentsAtOffset(nextObj,
                                                             nextOffset)
             self._nextLineContents = nextLineContents
         else:
@@ -5319,7 +5316,7 @@
             # we go to get them.  So...we'll just keep going backwards
             # until we find a real child that we can work with.]]]
             #
-            while not isinstance(previousObj, 
+            while not isinstance(previousObj,
                                  pyatspi.Accessibility.Accessible) \
                 and index >= 0:
                 previousObj = obj.parent[index]
@@ -5507,11 +5504,11 @@
                             False)
                 retval = self.findPrevByMatchRule(col, rule, wrap, currentObj)
                 # we created the matchRule so we need to free it
-                col.freeMatchRule(rule)            
+                col.freeMatchRule(rule)
                 return retval
             except:
                 # we have created our matchRule at this point so free it
-                col.freeMatchRule(rule) 
+                col.freeMatchRule(rule)
                 debug.printException(debug.LEVEL_SEVERE)
                 # Collection is probably not implemented, use the fallback
                 return self.iterFindPreviousRole(roles, wrap, currentObj)
@@ -5583,7 +5580,7 @@
                             False)
                 retval = self.findNextByMatchRule(col, rule, wrap, currentObj)
                 # we created the matchRule so we need to free it
-                col.freeMatchRule(rule)            
+                col.freeMatchRule(rule)
                 return retval
             except:
                 # we created the matchRule at this point so free it
@@ -5638,12 +5635,12 @@
 
         return [None, wrapped]
 
-    def findPrevByMatchRule(self, col, matchrule, 
+    def findPrevByMatchRule(self, col, matchrule,
                                   wrap, currentObj, allowNesting=False):
         # get our current object
         if not currentObj:
             [currentObj, characterOffset] = self.getCaretContext()
-            
+
         # Get the ancestors.  We won't stop on any of them.
         ancestors = []
         obj = currentObj.parent
@@ -5655,8 +5652,8 @@
                 obj = obj.parent
 
         wrapped = False
-        rs = col.getMatchesTo(currentObj, matchrule, 
-                              col.SORT_ORDER_CANONICAL, 
+        rs = col.getMatchesTo(currentObj, matchrule,
+                              col.SORT_ORDER_CANONICAL,
                               col.TREE_INORDER, True, 1, True)
         while True:
             if len(rs) == 0:
@@ -5666,19 +5663,19 @@
                     lastobj = self.getLastObject()
                     # Collection does not do an inclusive search, meaning
                     # that the start object is not part of the search.  So
-                    # we need to test the lastobj separately using the given 
+                    # we need to test the lastobj separately using the given
                     # matchRule.  We don't have this problem for 'Next' because
                     # the startobj is the doc frame.
                     #
                     secondlastobj = self.findPreviousObject(lastobj)
-                    rs = col.getMatchesFrom(secondlastobj, matchrule, 
-                              col.SORT_ORDER_CANONICAL, 
+                    rs = col.getMatchesFrom(secondlastobj, matchrule,
+                              col.SORT_ORDER_CANONICAL,
                               col.TREE_INORDER, 1, True)
                     if len(rs) > 0:
                         return [rs[0], True]
                     else:
-                        rs = col.getMatchesTo(lastobj, matchrule, 
-                              col.SORT_ORDER_CANONICAL, 
+                        rs = col.getMatchesTo(lastobj, matchrule,
+                              col.SORT_ORDER_CANONICAL,
                               col.TREE_INORDER, True, 1, True)
                         wrapped = True
                  # caller doesn't want us to wrap and we haven't found anything
@@ -5686,41 +5683,41 @@
                     return [None, False]
             elif len(rs) > 0:
                 if rs[0] in ancestors:
-                    rs = col.getMatchesTo(rs[0], matchrule, 
-                              col.SORT_ORDER_CANONICAL, 
+                    rs = col.getMatchesTo(rs[0], matchrule,
+                              col.SORT_ORDER_CANONICAL,
                               col.TREE_INORDER, True, 1, True)
                 else:
                     return [rs[0], wrapped]
-                 
+
     def findNextByMatchRule(self, col, matchrule, wrap, currentObj=None):
         # get our current object
         if not currentObj:
             [currentObj, characterOffset] = self.getCaretContext()
 
         # go find the next match
-        rs = col.getMatchesFrom(currentObj, 
+        rs = col.getMatchesFrom(currentObj,
                                     matchrule,
                                     col.SORT_ORDER_CANONICAL,
                                     col.TREE_INORDER,
-                                    1, 
+                                    1,
                                     True)
 
         if len(rs) > 0:
             return [rs[0], False]
         elif wrap:
             # We didn't find anything so start at the doc frame and try again
-            rs = col.getMatchesFrom(self.getDocumentFrame(), 
+            rs = col.getMatchesFrom(self.getDocumentFrame(),
                                     matchrule,
                                     col.SORT_ORDER_CANONICAL,
                                     col.TREE_INORDER,
-                                    1, 
+                                    1,
                                     True)
             if len(rs) > 0:
                 return [rs[0], True]
             else:
                 return [None, True]
         else:
-            return [None, False] 
+            return [None, False]
 
     def findPrevByPredicate(self, pred, wrap, currentObj=None):
         """Finds the caret offset at the beginning of the previous object
@@ -5764,7 +5761,7 @@
                     wrapped = True
 
         return [None, wrapped]
-                
+
     def findNextByPredicate(self, pred, wrap, currentObj=None):
         """Finds the caret offset at the beginning of the next object
         using the given predicate as a pattern to match or not match.
@@ -5844,7 +5841,7 @@
         self._updateLineCache(obj, characterOffset)
 
     def getTextLineAtCaret(self, obj):
-        """Gets the line of text where the caret is. This is an override to 
+        """Gets the line of text where the caret is. This is an override to
         accomodate the intricities of our caret navigation management.
 
         Argument:
@@ -5863,7 +5860,7 @@
         if contextObj == obj:
             if not obj.getState().contains(pyatspi.STATE_EDITABLE):
                 caretOffset = contextCaret
-        
+
         return string, caretOffset, startOffset
 
     def getCaretContext(self, includeNonText=True):
@@ -6025,7 +6022,7 @@
                 # difference is 1, then we're moving down and want the
                 # text that comes after this offset.  Otherwise, we're
                 # moving up and want the text that comes after the end.
-                # 
+                #
                 if offset - end > 1:
                     offset = end + 1
                 [line, start, end] = text.getTextAfterOffset(end + 1, boundary)
@@ -6166,7 +6163,7 @@
 
         elif not self.queryNonEmptyText(obj):
             return [[obj, -1, -1]]
-        
+
         text = self.getUnicodeText(obj)
         for offset in range(characterOffset, len(text)):
             if text[offset] == self.EMBEDDED_OBJECT_CHARACTER:
@@ -6284,9 +6281,9 @@
 
         # Pylint is confused and flags these errors:
         #
-        # E1101:6957:Script.getUtterancesFromContents: Instance of 
+        # E1101:6957:Script.getUtterancesFromContents: Instance of
         # 'SpeechGenerator' has no 'getSpeechForObjectRole' member
-        # E1101:6962:Script.getUtterancesFromContents: Instance of 
+        # E1101:6962:Script.getUtterancesFromContents: Instance of
         # 'SpeechGenerator' has no 'getSpeechForObjectRole' member
         #
         # So for now, we just disable these errors in this method.
@@ -6364,7 +6361,8 @@
         character = self.getCharacterAtOffset(obj, characterOffset)
         if obj:
             if character and character != self.EMBEDDED_OBJECT_CHARACTER:
-                speech.speak(character, self.getACSS(obj, character), False)
+                speech.speakCharacter(character,
+                                      self.getACSS(obj, character))
             elif obj.getRole() != pyatspi.ROLE_ENTRY:
                 # We won't have a character if we move to the end of an
                 # entry (in which case we're not on a character and therefore
@@ -6613,11 +6611,11 @@
 
         prevObj = currentLine[0][0]
         prevOffset = currentLine[0][1]
-        [prevObj, prevOffset] = self.findPreviousCaretInOrder(prevObj, 
+        [prevObj, prevOffset] = self.findPreviousCaretInOrder(prevObj,
                                                               prevOffset)
 
         if self.isLineBreakChar(prevObj, prevOffset):
-            [prevObj, prevOffset] = self.findPreviousCaretInOrder(prevObj, 
+            [prevObj, prevOffset] = self.findPreviousCaretInOrder(prevObj,
                                                                   prevOffset)
 
         # If the user did some back-to-back arrowing, we might already have
@@ -6627,7 +6625,7 @@
         index = self.findObjectOnLine(prevObj, prevOffset, prevLine)
         if index < 0:
             prevLine = self.getLineContentsAtOffset(prevObj, prevOffset)
-    
+
         if not prevLine:
             return [None, -1]
 
@@ -6649,12 +6647,12 @@
             prevObj = self.findPreviousObject(prevObj)
             prevOffset = 0
 
-        [prevObj, prevOffset] = self.findNextCaretInOrder(prevObj, 
+        [prevObj, prevOffset] = self.findNextCaretInOrder(prevObj,
                                                           prevOffset - 1)
 
         if not arrowToLineBeginning:
-            extents = self.getExtents(obj, 
-                                      characterOffset, 
+            extents = self.getExtents(obj,
+                                      characterOffset,
                                       characterOffset + 1)
             oldX = extents[0]
             for item in prevLine:
@@ -6743,7 +6741,7 @@
 
         if not arrowToLineBeginning:
             extents = self.getExtents(obj,
-                                      characterOffset, 
+                                      characterOffset,
                                       characterOffset + 1)
             oldX = extents[0]
             for item in nextLine:
@@ -6908,7 +6906,7 @@
         Arguments:
         - desiredLevel: the level (1-6) of the heading to locate
         """
-        
+
         found = False
         level = 0
         [obj, characterOffset] = self.getCaretContext()
@@ -6939,7 +6937,7 @@
             self.setCaretPosition(obj, characterOffset)
             self.updateBraille(obj)
             contents = self.getObjectContentsAtOffset(obj, characterOffset)
-            self.speakContents(contents)             
+            self.speakContents(contents)
         else:
             # Translators: this is in reference to navigating HTML content
             # by heading (e.g., <h1>).
@@ -7091,18 +7089,18 @@
 
         # Try to find it using Collection first
         success = False
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
                 found = False
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 # form our list of attribute strings
                 attrs = []
                 for landmark in ARIA_LANDMARKS:
                     attrs.append('xml-roles:' + landmark)
                 # define matchRule and find it
                 stateset = pyatspi.StateSet()
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              attrs, col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7111,7 +7109,7 @@
                 if obj != startobj:
                     found = True
                 success = True
-                col.freeMatchRule(rule)   
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7120,7 +7118,7 @@
 
         # Do it iteratively when Collection failed or is disabled
         if not success or not settings.useCollection:
-            [obj, wrapped] = self.findPrevByPredicate(self.__matchLandmark, 
+            [obj, wrapped] = self.findPrevByPredicate(self.__matchLandmark,
                                                       True, obj)
         if wrapped:
             # Translators: when the user is attempting to locate a
@@ -7138,9 +7136,9 @@
                                                               characterOffset))
         else:
             # Translators: this is for navigating to the previous ARIA
-            # role landmark.  ARIA role landmarks are the W3C defined HTML 
-            # tag attribute 'role' used to identify important part of 
-            # webpage like banners, main context, search etc.  This is an 
+            # role landmark.  ARIA role landmarks are the W3C defined HTML
+            # tag attribute 'role' used to identify important part of
+            # webpage like banners, main context, search etc.  This is an
             # that one was not found.
             #
             speech.speak(_("No landmark found."))
@@ -7150,17 +7148,17 @@
 
         # Try to find it using Collection first
         success = False
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 # form our list of attribute strings
                 attrs = []
                 for landmark in ARIA_LANDMARKS:
                     attrs.append('xml-roles:' + landmark)
                 # define matchRule and find it
                 stateset = pyatspi.StateSet()
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              attrs, col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7170,8 +7168,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7180,7 +7178,7 @@
 
         # Do it iteratively when Collection failed or is disabled
         if not success or not settings.useCollection:
-            [obj, wrapped] = self.findNextByPredicate(self.__matchLandmark, 
+            [obj, wrapped] = self.findNextByPredicate(self.__matchLandmark,
                                                       True, obj)
         if wrapped:
             # Translators: when the user is attempting to locate a
@@ -7227,9 +7225,9 @@
         while line and not found:
             index = self.findObjectOnLine(prevObj, prevOffset, useful)
             if not self.isSameObject(obj, prevObj):
-                # The question is, have we found the beginning of this 
+                # The question is, have we found the beginning of this
                 # object?  If the offset is 0 or there's more than one
-                # object on this line and we started on a later line, 
+                # object on this line and we started on a later line,
                 # it's safe to assume we've found the beginning.
                 #
                 found = (prevOffset == 0) \
@@ -7327,7 +7325,7 @@
                 found = True
             else:
                 self._previousLineContents = line
-                [nextObj, nextOffset] = self.findNextLine(line[-1][0], 
+                [nextObj, nextOffset] = self.findNextLine(line[-1][0],
                                                           line[-1][2])
                 line = self.currentLineContents
                 if self.currentLineContents == self._previousLineContents:
@@ -7366,25 +7364,25 @@
         success = False
 
         # Try to find it using Collection first
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_FOCUSABLE)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LIST], col.MATCH_ANY,
                              "", col.MATCH_ALL,
                              False)
-                [obj, wrapped] = self.findPrevByMatchRule(col, 
+                [obj, wrapped] = self.findPrevByMatchRule(col,
                                           rule, True, obj, allowNesting = True)
                 if obj and obj != startobj:
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7400,7 +7398,7 @@
                 #
                 if wrapped:
                     wrap = False
-    
+
                 # We need to be sure that the list in question is an (un)ordered
                 # list rather than a list in a form field. Form field lists are
                 # focusable; (un)ordered lists are not.
@@ -7456,14 +7454,14 @@
         wrap = True
         success = False
 
-        # Try to find it using Collection first    
-        if settings.useCollection:       
+        # Try to find it using Collection first
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_FOCUSABLE)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LIST], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7473,8 +7471,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7490,7 +7488,7 @@
                 #
                 if wrapped:
                     wrap = False
-    
+
                 # We need to be sure that the list in question is an (un)ordered
                 # list rather than a list in a form field. Form field lists are
                 # focusable; (un)ordered lists are not.
@@ -7547,13 +7545,13 @@
         success = False
 
         # Try to find it using Collection first
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_FOCUSABLE)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LIST_ITEM], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7563,8 +7561,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7580,10 +7578,10 @@
                 #
                 if wrapped:
                     wrap = False
-    
-                # We need to be sure that the list item in question is the 
-                # child of an (un)ordered list rather than a list in a form 
-                # field. Form field list items are focusable; (un)ordered 
+
+                # We need to be sure that the list item in question is the
+                # child of an (un)ordered list rather than a list in a form
+                # field. Form field list items are focusable; (un)ordered
                 # list items are not.
                 #
                 if obj and \
@@ -7616,14 +7614,14 @@
         wrap = True
         success = False
 
-        # Try to find it using Collection first    
-        if settings.useCollection:       
+        # Try to find it using Collection first
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_FOCUSABLE)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LIST_ITEM], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7633,8 +7631,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7650,10 +7648,10 @@
                 #
                 if wrapped:
                     wrap = False
-    
-                # We need to be sure that the list item in question is the 
-                # child of an (un)ordered list rather than a list in a form 
-                # field. Form field list items are focusable; (un)ordered 
+
+                # We need to be sure that the list item in question is the
+                # child of an (un)ordered list rather than a list in a form
+                # field. Form field list items are focusable; (un)ordered
                 # list items are not.
                 #
                 if obj and \
@@ -7698,13 +7696,13 @@
         found = False
 
         # Try to find it using Collection first
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_VISITED)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LINK], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7714,8 +7712,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7724,7 +7722,7 @@
 
         # Do it iteratively when Collection failed or is disabled
         if not success or not settings.useCollection:
-            
+
             while obj and not found:
                 [obj, wrapped] = \
                     self.findPreviousRole([pyatspi.ROLE_LINK], wrap, obj)
@@ -7765,13 +7763,13 @@
         found = False
 
         # Try to find it using Collection first
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_VISITED)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_NONE,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LINK], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7781,8 +7779,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except AttributeError:
@@ -7841,13 +7839,13 @@
         found = False
 
         # Try to find it using Collection first
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_VISITED)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LINK], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7857,8 +7855,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7906,14 +7904,14 @@
         found = False
         wrap = True
 
-        # Try to find it using Collection first    
-        if settings.useCollection:       
+        # Try to find it using Collection first
+        if settings.useCollection:
             try:
                 startobj = obj
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
                 stateset.add(pyatspi.STATE_VISITED)
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              [pyatspi.ROLE_LINK], col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7923,8 +7921,8 @@
                     found = True
                 else:
                     found = False
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -7932,7 +7930,7 @@
                 col.freeMatchRule(rule)
 
         # Do it iteratively when Collection failed or is disabled
-        if not success or not settings.useCollection: 
+        if not success or not settings.useCollection:
             while obj and not found:
                 [obj, wrapped] = \
                     self.findNextRole([pyatspi.ROLE_LINK], wrap, obj)
@@ -7983,13 +7981,13 @@
 
         # Try to find it using Collection first
         success = False
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
                 found = False
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              ['tag:BLOCKQUOTE'], col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -7998,7 +7996,7 @@
                 if obj != startobj:
                     found = True
                 success = True
-                col.freeMatchRule(rule)   
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -8006,7 +8004,7 @@
                 col.freeMatchRule(rule)
 
         # Do it iteratively when Collection failed or is disabled
-        if not success or not settings.useCollection: 
+        if not success or not settings.useCollection:
             currentObj = obj
             found = False
             wrapped = False
@@ -8053,13 +8051,13 @@
 
         # Try to find it using Collection first
         success = False
-        if settings.useCollection:       
+        if settings.useCollection:
             try:
                 startobj = obj
                 found = False
-                col = self.getDocumentFrame().queryCollection() 
+                col = self.getDocumentFrame().queryCollection()
                 stateset = pyatspi.StateSet()
-                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,  
+                rule = col.createMatchRule(stateset.raw(), col.MATCH_ANY,
                              ['tag:BLOCKQUOTE'], col.MATCH_ANY,
                              "", col.MATCH_ANY,
                              "", col.MATCH_ALL,
@@ -8067,8 +8065,8 @@
                 [obj, wrapped] = self.findNextByMatchRule(col, rule, True, obj)
                 if obj and obj not in ancestors:
                     found = True
-                success = True 
-                col.freeMatchRule(rule)  
+                success = True
+                col.freeMatchRule(rule)
             except NotImplementedError:
                 debug.printException(debug.LEVEL_SEVERE)
             except:
@@ -8076,7 +8074,7 @@
                 col.freeMatchRule(rule)
 
         # Do it iteratively when Collection failed or is disabled
-        if not success or not settings.useCollection: 
+        if not success or not settings.useCollection:
             currentObj = obj
             found = False
             wrapped = False
@@ -8608,7 +8606,7 @@
 
     def goNextLiveRegion(self, inputEvent):
         # First, get any live regions that have been registered as LIVE_NONE
-        # because there is no markup to test for these but we still want to 
+        # because there is no markup to test for these but we still want to
         # find them
         regobjs = self.liveMngr.getLiveNoneObjects()
         # define our search predicate
@@ -8627,7 +8625,7 @@
             #
             speech.speak(_("Wrapping to top."))
         if obj:
-            # TODO:   We don't want to move to a list item.  
+            # TODO:   We don't want to move to a list item.
             # Is this the best place to handle this?
             if obj.getRole() == pyatspi.ROLE_LIST:
                 characterOffset = 0
@@ -8649,7 +8647,7 @@
 
     def goPreviousLiveRegion(self, inputEvent):
         # First, get any live regions that have been registered as LIVE_NONE
-        # because there is no markup to test for these but we still want to 
+        # because there is no markup to test for these but we still want to
         # find them
         regobjs = self.liveMngr.getLiveNoneObjects()
         # define our search predicate
@@ -8668,7 +8666,7 @@
             #
             speech.speak(_("Wrapping to top."))
         if obj:
-            # TODO:   We don't want to move to a list item.  
+            # TODO:   We don't want to move to a list item.
             # Is this the best place to handle this?
             if obj.getRole() == pyatspi.ROLE_LIST:
                 characterOffset = 0
@@ -8685,7 +8683,7 @@
             # that are updated without having to refresh the entire page.
             #
             speech.speak(_("No more live regions."))
-            
+
     def goLastLiveRegion(self, inputEvent):
         if settings.inferLiveRegions:
             self.liveMngr.goLastLiveRegion()
@@ -8704,7 +8702,7 @@
             # support has been turned off.
             #
             speech.speak(_("Live region support is off"))
-            
+
     def monitorLiveRegions(self, inputEvent):
         if not settings.inferLiveRegions:
             settings.inferLiveRegions = True
@@ -8719,7 +8717,7 @@
             #
             self.liveMngr.flushMessages()
             speech.speak(_("Live regions monitoring off"))
-            
+
     def setLivePolitenessOff(self, inputEvent):
         if settings.inferLiveRegions:
             self.liveMngr.setLivePolitenessOff()
@@ -8808,9 +8806,7 @@
         debug.println(debug.LEVEL_CONFIGURATION, string)
         speech.speak(string)
         braille.displayMessage(string)
-        
 
-
     def speakWordUnderMouse(self, acc):
         """Determine if the speak-word-under-mouse capability applies to
         the given accessible.
Index: src/orca/default.py
===================================================================
--- src/orca/default.py	(revision 3893)
+++ src/orca/default.py	(working copy)
@@ -64,7 +64,6 @@
 import speechserver
 import mouse_review
 
-
 from orca_i18n import _         # for gettext support
 from orca_i18n import ngettext  # for ngettext support
 from orca_i18n import Q_        # to provide qualified translatable strings
@@ -611,7 +610,7 @@
                 # Translators: this is a debug message that Orca users
                 # will not normally see. It describes a debug routine
                 # that outputs useful information on the current script
-                #  via speech and braille. This information will be 
+                #  via speech and braille. This information will be
                 # helpful to script writers.
                 #
                 _("Reports information on current script."))
@@ -770,7 +769,7 @@
         self.inputEventHandlers["cycleDebugLevelHandler"] = \
             input_event.InputEventHandler(
                 orca.cycleDebugLevel,
-                # Translators: this is a debug message that Orca users 
+                # Translators: this is a debug message that Orca users
                 # will not normally see. It describes a debug routine
                 # that allows the user to adjust the level of debug
                 # information that Orca generates at run time.
@@ -791,7 +790,7 @@
         self.inputEventHandlers["printAncestryHandler"] = \
             input_event.InputEventHandler(
                 Script.printAncestryHandler,
-                # Translators: this is a debug message that Orca users 
+                # Translators: this is a debug message that Orca users
                 # will not normally see. It describes a debug routine
                 # that will take the component in the currently running
                 # application that has focus, and print debug information
@@ -805,10 +804,10 @@
         self.inputEventHandlers["printHierarchyHandler"] = \
             input_event.InputEventHandler(
                 Script.printHierarchyHandler,
-                # Translators: this is a debug message that Orca users 
+                # Translators: this is a debug message that Orca users
                 # will not normally see. It describes a debug routine
                 # that will take the currently running application, and
-                # print debug information to the console giving its 
+                # print debug information to the console giving its
                 # component hierarchy (i.e. all the components and all
                 # their descendants in the component tree).
                 #
@@ -817,21 +816,21 @@
         self.inputEventHandlers["printMemoryUsageHandler"] = \
             input_event.InputEventHandler(
                 Script.printMemoryUsageHandler,
-                # Translators: this is a debug message that Orca users 
+                # Translators: this is a debug message that Orca users
                 # will not normally see. It describes a debug routine
                 # that will print Orca memory usage information.
                 #
                 _("Prints memory usage information."))
-                        
+
         self.inputEventHandlers["bookmarkCurrentWhereAmI"] = \
             input_event.InputEventHandler(
                 Script.bookmarkCurrentWhereAmI,
                 # Translators: this command announces information regarding
-                # the relationship of the given bookmark to the current 
+                # the relationship of the given bookmark to the current
                 # position
                 #
-                _("Bookmark where am I with respect to current position."))    
-                
+                _("Bookmark where am I with respect to current position."))
+
         self.inputEventHandlers["goToBookmark"] = \
             input_event.InputEventHandler(
                 Script.goToBookmark,
@@ -839,23 +838,23 @@
                 # location stored at the bookmark.
                 #
                 _("Go to bookmark."))
-                
+
         self.inputEventHandlers["addBookmark"] = \
             input_event.InputEventHandler(
                 Script.addBookmark,
-                # Translators: this event handler binds an in-page accessible 
+                # Translators: this event handler binds an in-page accessible
                 # object location to the given input key command.
                 #
                 _("Add bookmark."))
-                
+
         self.inputEventHandlers["saveBookmarks"] = \
             input_event.InputEventHandler(
                 Script.saveBookmarks,
-                # Translators: this event handler saves all bookmarks for the 
+                # Translators: this event handler saves all bookmarks for the
                 # current application to disk.
                 #
                 _("Save bookmarks."))
-                
+
         self.inputEventHandlers["goToNextBookmark"] = \
             input_event.InputEventHandler(
                 Script.goToNextBookmark,
@@ -863,12 +862,12 @@
                 # bookmarks and takes the user to the next bookmark location.
                 #
                 _("Go to next bookmark location."))
-                
+
         self.inputEventHandlers["goToPrevBookmark"] = \
             input_event.InputEventHandler(
                 Script.goToPrevBookmark,
-                # Translators: this event handler cycles through the 
-                # registered bookmarks and takes the user to the previous 
+                # Translators: this event handler cycles through the
+                # registered bookmarks and takes the user to the previous
                 # bookmark location.
                 #
                 _("Go to previous bookmark location."))
@@ -1755,31 +1754,31 @@
         #                                                                   #
         #  Bookmark key bindings                                            #
         #                                                                   #
-        #####################################################################   
-        # key binding to save bookmark information to disk 
+        #####################################################################
+        # key binding to save bookmark information to disk
         keyBindings.add(
             keybindings.KeyBinding(
                 "b",
                 orcaShiftAltModMask,
                 orcaAltModMask,
-                self.inputEventHandlers["saveBookmarks"])) 
-        # key binding to move to the previous bookmark         
+                self.inputEventHandlers["saveBookmarks"]))
+        # key binding to move to the previous bookmark
         keyBindings.add(
             keybindings.KeyBinding(
                 "b",
                 orcaShiftAltModMask,
                 orcaShiftModMask,
-                self.inputEventHandlers["goToPrevBookmark"])) 
-        # key binding to move to the next bookmark             
+                self.inputEventHandlers["goToPrevBookmark"]))
+        # key binding to move to the next bookmark
         keyBindings.add(
             keybindings.KeyBinding(
                 "b",
                 orcaShiftAltModMask,
                 orcaModMask,
-                self.inputEventHandlers["goToNextBookmark"]))    
-                
-        # key bindings for '1' through '6' for relevant commands            
-        for key in xrange(1, 7):  
+                self.inputEventHandlers["goToNextBookmark"]))
+
+        # key bindings for '1' through '6' for relevant commands
+        for key in xrange(1, 7):
             # 'Add bookmark' key bindings
             keyBindings.add(
                 keybindings.KeyBinding(
@@ -1787,7 +1786,7 @@
                     orcaShiftAltModMask,
                     orcaAltModMask,
                     self.inputEventHandlers["addBookmark"]))
-                    
+
             # 'Go to bookmark' key bindings
             keyBindings.add(
                 keybindings.KeyBinding(
@@ -1795,8 +1794,8 @@
                     orcaShiftAltModMask,
                     orcaModMask,
                     self.inputEventHandlers["goToBookmark"]))
-                    
-            # key binding for WhereAmI information with respect to root acc 
+
+            # key binding for WhereAmI information with respect to root acc
             keyBindings.add(
                 keybindings.KeyBinding(
                     str(key),
@@ -1993,7 +1992,6 @@
         if text.getNSelections():
             text.setSelection(0, context.currentOffset, context.currentOffset)
 
-
     def sayAll(self, inputEvent):
         clickCount = self.getClickCount()
         doubleClick = clickCount == 2
@@ -2157,13 +2155,13 @@
             lastChar = lastWord[len(lastWord) - 1]
             if lastChar == "\n" and lastWord != word:
                 voice = self.voices[settings.DEFAULT_VOICE]
-                speech.speak(chnames.getCharacterName("\n"), voice, False)
+                speech.speakCharacter("\n", voice)
 
         if lastKey == "Left" and len(word) > 0:
             lastChar = word[len(word) - 1]
             if lastChar == "\n" and lastWord != word:
                 voice = self.voices[settings.DEFAULT_VOICE]
-                speech.speak(chnames.getCharacterName("\n"), voice, False)
+                speech.speakCharacter("\n", voice)
 
         if self.getLinkIndex(obj, offset) >= 0:
             voice = self.voices[settings.HYPERLINK_VOICE]
@@ -2343,14 +2341,14 @@
             if prevChar == "\n":
                 # The cursor is at the beginning of a line.
                 # Speak a newline.
-                speech.speak(chnames.getCharacterName("\n"), voice, False)
+                speech.speakCharacter("\n", voice)
 
         # Handle speaking newlines when the left-arrow key is pressed.
         elif orca_state.lastNonModifierKeyEvent.event_string == "Left":
             if character == "\n":
                 # The cursor is at the end of a line.
                 # Speak a newline.
-                speech.speak(chnames.getCharacterName("\n"), voice, False)
+                speech.speakCharacter("\n", voice)
 
         if character == "\n":
             if prevChar == "\n":
@@ -2362,9 +2360,8 @@
                     #
                     speech.speak(_("blank"), voice, False)
         else:
-            speech.speak(chnames.getCharacterName(character), voice, False)
+            speech.speakCharacter(character, voice)
 
-
     def presentTooltip(self, obj):
         """
         Speaks the tooltip for the current object of interest.
@@ -2613,7 +2610,7 @@
             newParent = None
 
         # Clear the point of reference.
-        # If the point of reference is a cell, we want to keep the 
+        # 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() == pyatspi.ROLE_TABLE:
@@ -2732,9 +2729,9 @@
                 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 
+            # 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.
             #
             rolesList = [pyatspi.ROLE_TABLE_CELL, \
@@ -2762,7 +2759,7 @@
                 #
                 utterances.append(_("tree level %d") % (newNodeLevel + 1))
 
-            # If this is an icon within an layered pane or a table cell 
+            # 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.
             #
@@ -2776,8 +2773,8 @@
                 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 
+            # 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 \
@@ -3028,7 +3025,7 @@
         # that it selected.]]]
         #
         role = event.source.getRole()
-        if role in (pyatspi.ROLE_MENU, 
+        if role in (pyatspi.ROLE_MENU,
                     pyatspi.ROLE_MENU_ITEM,
                     pyatspi.ROLE_CHECK_MENU_ITEM,
                     pyatspi.ROLE_RADIO_MENU_ITEM):
@@ -3047,12 +3044,12 @@
         #
         newFocus = event.source
 
-        if role in (pyatspi.ROLE_LAYERED_PANE, 
+        if role in (pyatspi.ROLE_LAYERED_PANE,
                     pyatspi.ROLE_TABLE,
                     pyatspi.ROLE_TREE_TABLE,
                     pyatspi.ROLE_TREE):
             if event.source.childCount:
-                # We might have tucked away some information for this 
+                # We might have tucked away some information for this
                 # thing in the onActiveDescendantChanged method.
                 #
                 if self.pointOfReference.has_key("activeDescendantInfo"):
@@ -3352,7 +3349,10 @@
         # right now because it is typically something else
         # related to this event.
         #
-        speech.speak(character, voice, False)
+        if len(character.decode('utf-8')) == 1:
+            speech.speakCharacter(character, voice)
+        else:
+            speech.speak(character, voice, False)
 
     def onTextInserted(self, event):
         """Called whenever text is inserted into an object.
@@ -3392,7 +3392,7 @@
         #
         if event.source.getRole() == pyatspi.ROLE_SPIN_BUTTON:
             # We are using getTextLineAtCaret here instead of the "text"
-            # variable, because of a problem with selected text in spin 
+            # variable, because of a problem with selected text in spin
             # buttons. See bug #520395 for more details.
             #
             [spinValue, caretOffset, startOffset] = \
@@ -3522,11 +3522,11 @@
                 return
 
         if event.type.startswith("object:state-changed:selected"):
-            # If this selection state change is for the object which 
+            # If this selection state change is for the object which
             # currently has the locus of focus, and the last keyboard
-            # event was Space, or we are a focused table cell and we 
-            # arrowed Down or Up and are now selected, then let the 
-            # user know the selection state. 
+            # event was Space, or we are a focused table cell and we
+            # arrowed Down or Up and are now selected, then let the
+            # user know the selection state.
             # See bugs #486908 and #519564 for more details.
             #
             if isinstance(orca_state.lastInputEvent,
@@ -3544,8 +3544,8 @@
                         if isControlKey:
                             announceState = True
                         else:
-                            # Weed out a bogus situation. If we are already 
-                            # selected and the user presses "space" again, 
+                            # Weed out a bogus situation. If we are already
+                            # selected and the user presses "space" again,
                             # we don't want to speak the intermediate
                             # "unselected" state.
                             #
@@ -3730,12 +3730,12 @@
         if not event or not event.source:
             return
 
-        # Save the event source, if it is a menu or combo box. It will be 
+        # Save the event source, if it is a menu or combo box. It will be
         # useful for optimizing getComponentAtDesktopCoords in the case
         # that the  pointer is hovering over a menu item. The alternative is
         # to traverse the application's tree looking for potential moused-over
         # menu items.
-        if event.source.getRole() in (pyatspi.ROLE_COMBO_BOX, 
+        if event.source.getRole() in (pyatspi.ROLE_COMBO_BOX,
                                            pyatspi.ROLE_MENU):
             self.lastSelectedMenu = event.source
 
@@ -4006,8 +4006,8 @@
                             # Translators: these represent the number of pixels
                             # for the left or right margins in a document.  We
                             # are hesitant to interpret the values -- they are
-                            # given to us in some unknown form by the 
-                            # application, so we leave things in plural form 
+                            # given to us in some unknown form by the
+                            # application, so we leave things in plural form
                             # here.
                             #
                             line = ngettext("%s %s pixel",
@@ -4297,7 +4297,7 @@
                 movedCaret = text.setCaretOffset(startOffset - 1)
 
             # If we didn't move the caret and we're in a terminal, we
-            # jump into flat review to review the text.  See 
+            # jump into flat review to review the text.  See
             # http://bugzilla.gnome.org/show_bug.cgi?id=482294.
             #
             if (not movedCaret) \
@@ -4877,46 +4877,46 @@
             self.find(lastQuery)
         else:
             orca.showFindGUI()
-            
-    def goToBookmark(self, inputEvent): 
-        """ Go to the bookmark indexed by inputEvent.hw_code.  Delegates to 
+
+    def goToBookmark(self, inputEvent):
+        """ Go to the bookmark indexed by inputEvent.hw_code.  Delegates to
         Bookmark.goToBookmark """
         bookmarks = self.getBookmarks()
         bookmarks.goToBookmark(inputEvent)
-    
-    def addBookmark(self, inputEvent): 
+
+    def addBookmark(self, inputEvent):
         """ Add an in-page accessible object bookmark for this key.
         Delegates to Bookmark.addBookmark """
         bookmarks = self.getBookmarks()
         bookmarks.addBookmark(inputEvent)
-    
+
     def bookmarkCurrentWhereAmI(self, inputEvent):
-        """ Report "Where am I" information for this bookmark relative to the 
-        current pointer location.  Delegates to 
-        Bookmark.bookmarkCurrentWhereAmI""" 
+        """ Report "Where am I" information for this bookmark relative to the
+        current pointer location.  Delegates to
+        Bookmark.bookmarkCurrentWhereAmI"""
         bookmarks = self.getBookmarks()
         bookmarks.bookmarkCurrentWhereAmI(inputEvent)
-    
-    def saveBookmarks(self, inputEvent): 
-        """ Save the bookmarks for this script. Delegates to 
+
+    def saveBookmarks(self, inputEvent):
+        """ Save the bookmarks for this script. Delegates to
         Bookmark.saveBookmarks """
         bookmarks = self.getBookmarks()
         bookmarks.saveBookmarks(inputEvent)
-    
-    def goToNextBookmark(self, inputEvent): 
+
+    def goToNextBookmark(self, inputEvent):
         """ Go to the next bookmark location.  If no bookmark has yet to be
-        selected, the first bookmark will be used.  Delegates to 
+        selected, the first bookmark will be used.  Delegates to
         Bookmark.goToNextBookmark """
         bookmarks = self.getBookmarks()
         bookmarks.goToNextBookmark(inputEvent)
-    
+
     def goToPrevBookmark(self, inputEvent):
-        """ Go to the previous bookmark location.  If no bookmark has yet to 
-        be selected, the first bookmark will be used.  Delegates to 
-        Bookmark.goToPrevBookmark """ 
+        """ Go to the previous bookmark location.  If no bookmark has yet to
+        be selected, the first bookmark will be used.  Delegates to
+        Bookmark.goToPrevBookmark """
         bookmarks = self.getBookmarks()
         bookmarks.goToPrevBookmark(inputEvent)
-           
+
 ########################################################################
 #                                                                      #
 # DEBUG support.                                                       #
@@ -5314,7 +5314,7 @@
         labelString = None
         labels = self.findDisplayedLabel(obj)
         for label in labels:
-            labelString = self.appendString(labelString, 
+            labelString = self.appendString(labelString,
                                             self.getDisplayedText(label))
 
         return labelString
@@ -5888,16 +5888,16 @@
         return newLine.encode("UTF-8")
 
     def _getPronunciationForSegment(self, segment):
-        """Adjust the word segment to potentially replace it with what 
+        """Adjust the word segment to potentially replace it with what
         those words actually sound like. Two pronunciation dictionaries
         are checked. First the application specific one (which might be
         empty), then the default (global) one.
 
-        Arguments: 
+        Arguments:
         - segment: the string to adjust for words in the pronunciation
           dictionaries.
 
-        Returns: a new word segment adjusted for words found in the 
+        Returns: a new word segment adjusted for words found in the
         pronunciation dictionaries, or the original word segment if there
         was no dictionary entry.
         """
@@ -6174,7 +6174,7 @@
             if not obj.getState().contains(pyatspi.STATE_EXPANDED):
                 return []
 
-        nodes = []        
+        nodes = []
         row = table.getRowAtIndex(obj.getIndexInParent())
         col = table.getColumnAtIndex(obj.getIndexInParent())
         nodeLevel = self.getNodeLevel(obj)
@@ -6212,7 +6212,6 @@
         Arguments:
         - obj: the Accessible object
 
-      
         Returns: list containing strings: [mnemonic, accelerator, shortcut]
         """
 
@@ -6763,7 +6762,7 @@
         return False
 
     def _saveSpokenTextRange(self, startOffset, endOffset):
-        """Save away the start and end offset of the range of text that 
+        """Save away the start and end offset of the range of text that
         was spoken. It will be used by speakTextSelectionState, to try
         to determine if the text was selected or unselected.
 
@@ -6861,7 +6860,7 @@
                 #
                 line = _("page selected to cursor position")
             else:
-                # Translators: when the user unselects text in a document, 
+                # Translators: when the user unselects text in a document,
                 # Orca will speak information about what they have unselected.
                 #
                 line = _("page unselected to cursor position")
@@ -6875,7 +6874,7 @@
                 #
                 line = _("line selected down from cursor position")
             else:
-                # Translators: when the user unselects text in a document, 
+                # Translators: when the user unselects text in a document,
                 # Orca will speak information about what they have unselected.
                 #
                 line = _("line unselected down from cursor position")
@@ -6889,7 +6888,7 @@
                 #
                 line = _("line selected up from cursor position")
             else:
-                # Translators: when the user unselects text in a document, 
+                # Translators: when the user unselects text in a document,
                 # Orca will speak information about what they have unselected.
                 #
                 line = _("line unselected up from cursor position")
@@ -6903,7 +6902,7 @@
                 #
                 line = _("document selected to cursor position")
             else:
-                # Translators: when the user unselects text in a document, 
+                # Translators: when the user unselects text in a document,
                 # Orca will speak information about what they have unselected.
                 #
                 line = _("document unselected to cursor position")
@@ -6917,7 +6916,7 @@
                 #
                 line = _("document selected from cursor position")
             else:
-                # Translators: when the user unselects text in a document, 
+                # Translators: when the user unselects text in a document,
                 # Orca will speak information about what they have unselected.
                 #
                 line = _("document unselected from cursor position")
@@ -6948,7 +6947,7 @@
             # the startOffset and endOffset to exclude them.
             #
             try:
-                tmpStr = text.getText(startOffset, 
+                tmpStr = text.getText(startOffset,
                                       endOffset).decode("UTF-8")
             except:
                 tmpStr = u''
@@ -7014,7 +7013,7 @@
         possibly subclassing whereamI for the Gecko script.
         """
         return None
-    
+
     def systemBeep(self):
         """Rings the system bell.  This is really a hack.  Ideally, we want
         a method that will present an earcon (any sound designated representing
@@ -7041,7 +7040,6 @@
         """Creates a Python dict from a typical attributes list returned from
         different AT-SPI methods.
 
-
         Arguments:
         - dict_string: A list of colon seperated key/value pairs seperated by
         semicolons.
@@ -7061,7 +7059,7 @@
         Arguments:
         - x: X coordinate.
         - y: Y coordinate.
-        
+
         Returns a menu item the mouse is over, or None.
         """
         suspect_children = []
@@ -7089,7 +7087,7 @@
         """Get the descendant component at the given desktop coordinates.
 
         Arguments:
-        
+
         - parent: The parent component we are searching below.
         - x: X coordinate.
         - y: Y coordinate.
@@ -7097,7 +7095,7 @@
         Returns end-node that contains the given coordinates, or None.
         """
         acc = self._getPopupItemAtDesktopCoords(x, y)
-        if acc: 
+        if acc:
             return acc
 
         container = parent
@@ -7131,8 +7129,8 @@
 
         Arguments:
         - acc: An accessible.
-        
-        Returns list of start and end offsets for multiple selections, or an 
+
+        Returns list of start and end offsets for multiple selections, or an
         empty list if nothing is selected or if the accessible does not support
         the text interface.
         """
@@ -7141,10 +7139,10 @@
             texti = acc.queryText()
         except:
             return rv
-       
+
         for i in xrange(texti.getNSelections()):
             rv.append(texti.getSelection(i))
-            
+
         return rv
 
     def speakWordUnderMouse(self, acc):
@@ -7165,9 +7163,9 @@
         - acc: An accessible.
         - offset: Offset in the accessible's text for which to retrieve the
         attributes.
-        - get_defaults: Get the default attributes as well as the unique ones. 
+        - get_defaults: Get the default attributes as well as the unique ones.
         Default is True
-        
+
         Returns a dictionary of attributes, a start offset where the attributes
         begin, and an end offset. Returns ({}, 0, 0) if the accessible does not
         supprt the text attribute.
@@ -7225,7 +7223,7 @@
                         end_offset = \
                             text_contents[start:end].index(' ', start_offset)
                     except ValueError:
-                        word_offsets.append((start_offset, 
+                        word_offsets.append((start_offset,
                                              len(text_contents[start:end])))
                         break
                     word_offsets.append((start_offset, end_offset))
@@ -7246,8 +7244,8 @@
 state_change_notifiers = {}
 
 state_change_notifiers[pyatspi.ROLE_CHECK_MENU_ITEM] = ("checked", None)
-state_change_notifiers[pyatspi.ROLE_CHECK_BOX]       = ("checked", 
-                                                        "indeterminate", 
+state_change_notifiers[pyatspi.ROLE_CHECK_BOX]       = ("checked",
+                                                        "indeterminate",
                                                         None)
 state_change_notifiers[pyatspi.ROLE_PANEL]           = ("showing", None)
 state_change_notifiers[pyatspi.ROLE_LABEL]           = ("showing", None)
Index: src/orca/orca.py
===================================================================
--- src/orca/orca.py	(revision 3893)
+++ src/orca/orca.py	(working copy)
@@ -679,9 +679,9 @@
 
     # See if this is one of our special Orca modifier keys.
     #
-    # Just looking at the keycode should suffice, but there is a 
-    # "feature" in the Java Access Bridge where it chooses to emit 
-    # Java platform-independent keycodes instead of the keycodes 
+    # Just looking at the keycode should suffice, but there is a
+    # "feature" in the Java Access Bridge where it chooses to emit
+    # Java platform-independent keycodes instead of the keycodes
     # for the base platform:
     #
     # http://bugzilla.gnome.org/show_bug.cgi?id=106004
@@ -934,7 +934,6 @@
         debug.println(debug.LEVEL_CONFIGURATION,
                       "Magnification module has NOT been initialized.")
 
-
     # I'm not sure where else this should go. But it doesn't really look
     # right here.
     try:
@@ -1060,7 +1059,7 @@
 
     props = { gnome.PARAM_APP_DATADIR : '/usr/share'}
     prog = gnome.program_init('orca', '1.0', properties=props)
-    gnome.help_display_with_doc_id(prog, 'gnome-access-guide', 
+    gnome.help_display_with_doc_id(prog, 'gnome-access-guide',
                                          'gnome-access-guide', 'ats-2')
 
     return True
@@ -1185,7 +1184,7 @@
 
     if settings.timeoutCallback and (settings.timeoutTime > 0):
         signal.alarm(0)
-    
+
     if settings.cacheValues:
         pyatspi.setCacheLevel(pyatspi.CACHE_PROPERTIES)
 
@@ -1313,7 +1312,7 @@
     print _("Usage: orca [OPTION...]")
     print
 
-    # Translators: this is the description of the command line option 
+    # Translators: this is the description of the command line option
     # '-?, --help' that is used to display usage information.
     #
     print "-?, --help                   " + _("Show this help message")
@@ -1321,22 +1320,22 @@
     print "-v, --version                %s" % platform.version
 
     # Translators: this is the description of the command line option
-    # '-s, --setup, --gui-setup' that will initially display a GUI dialog 
+    # '-s, --setup, --gui-setup' that will initially display a GUI dialog
     # that would allow the user to set their Orca preferences.
     #
     print "-s, --setup, --gui-setup     " + _("Set up user preferences")
 
-    # Translators: this is the description of the command line option 
-    # '-t, --text-setup' that will initially display a list of questions 
-    # in text form, that the user will need to answer, before Orca will 
-    # startup. For this to happen properly, Orca will need to be run 
+    # Translators: this is the description of the command line option
+    # '-t, --text-setup' that will initially display a list of questions
+    # in text form, that the user will need to answer, before Orca will
+    # startup. For this to happen properly, Orca will need to be run
     # from a terminal window.
     #
     print "-t, --text-setup             " + \
           _("Set up user preferences (text version)")
 
-    # Translators: this is the description of the command line option 
-    # '-n, --no-setup' that means that Orca will startup without setting 
+    # Translators: this is the description of the command line option
+    # '-n, --no-setup' that means that Orca will startup without setting
     # up any user preferences.
     #
     print "-n, --no-setup               " +  \
@@ -1344,7 +1343,7 @@
 
     # Translators: by default, Orca expects to find its user preferences
     # in a directory called .orca under the user's home directory. This
-    # is the description of the command line option 
+    # is the description of the command line option
     # '-u, --user-prefs-dir=dirname' that allows you to specify an alternate
     # location for those user preferences.
     #
@@ -1375,7 +1374,7 @@
     # command line option, it will be automatically disabled as Orca is
     # started.
     #
-    print _("Prevent use of option") 
+    print _("Prevent use of option")
 
     # Translators: this is the Orca command line option that will quit Orca.
     # The user would run the Orca shell script again from a terminal window.
@@ -1387,14 +1386,14 @@
 
     print
 
-    # Translators: this is text being sent to a terminal and we want to 
+    # Translators: this is text being sent to a terminal and we want to
     # keep the text lines within terminal boundaries.
     #
     print _("If Orca has not been previously set up by the user, Orca\n" \
             "will automatically launch the preferences set up unless\n" \
             "the -n or --no-setup option is used.")
 
-    # Translators: this is more text being sent to a terminal and we want to 
+    # Translators: this is more text being sent to a terminal and we want to
     # keep the text lines within terminal boundaries.
     #
     print
@@ -1505,7 +1504,7 @@
                 elif feature == Q_("option|braille"):
                     _commandLineSettings["enableBraille"] = True
 
-                # Translators: this option is for enabling a GUI to monitor 
+                # Translators: this option is for enabling a GUI to monitor
                 # what is being sent to the physical braille display.
                 #
                 # ONLY TRANSLATE THE PART AFTER THE PIPE CHARACTER |
@@ -1513,7 +1512,7 @@
                 elif feature == Q_("option|braille-monitor"):
                     _commandLineSettings["enableBrailleMonitor"] = True
 
-                # Translators: this option is for enabling screen 
+                # Translators: this option is for enabling screen
                 # magnification.
                 #
                 # ONLY TRANSLATE THE PART AFTER THE PIPE CHARACTER |
Index: src/orca/speech.py
===================================================================
--- src/orca/speech.py	(revision 3893)
+++ src/orca/speech.py	(working copy)
@@ -31,6 +31,7 @@
 
 import time
 
+import chnames
 import debug
 import keynames
 import orca
@@ -197,7 +198,7 @@
 
 def speakCharacter(character, acss=None):
     """Speaks a single character immediately.
-    
+
     Arguments:
     - character: text to be spoken
     - acss:      acss.ACSS instance; if None,
@@ -209,6 +210,7 @@
     if settings.silenceSpeech:
         return
 
+    character = chnames.getCharacterName(character)
     debug.println(debug.LEVEL_INFO, "SPEECH OUTPUT: '" + character + "'")
     log.info("SPEECH OUTPUT: '%s'" % character)
 
Index: src/orca/gnomespeechfactory.py
===================================================================
--- src/orca/gnomespeechfactory.py	(revision 3893)
+++ src/orca/gnomespeechfactory.py	(working copy)
@@ -454,7 +454,7 @@
         speaker = _Speaker(s._narrow(GNOME.Speech.Speaker))
 
         # Turn off punctuation.  We do this because we want to handle
-        # spoken punctuation on our own.  Only do so if "punctuation mode" 
+        # spoken punctuation on our own.  Only do so if "punctuation mode"
         # is available (see # bug #528797).
         #
         try:
@@ -652,7 +652,7 @@
                      used to augment/override the default
                      voice settings.
         """
-        self.speak(character, acss)
+        self.speak(chnames.getCharacterName(character), acss)
 
     def speakUtterances(self, utterances, acss=None, interrupt=True):
         """Speaks the given list of utterances immediately.
@@ -881,6 +881,13 @@
         if self.__sayAll:
             self.stop()
 
+        if not acss and text and text.isupper():
+            try:
+                acss = \
+                    orca_state.activeScript.voices[settings.UPPERCASE_VOICE]
+            except:
+                pass
+
         self.__speak(text, acss, interrupt)
 
     def isSpeaking(self):
