[orca] Fix for bgo#620163 - There should be a script utility to get the last key and modifiers



commit 64cdfd02b0f5a914115d963262a9251ef5358505
Author: Joanmarie Diggs <joanmarie diggs gmail com>
Date:   Mon May 31 12:40:24 2010 -0400

    Fix for bgo#620163 - There should be a script utility to get the last key and modifiers

 src/orca/chat.py                                   |    6 +-
 src/orca/default.py                                |  225 ++++++++------------
 src/orca/script_utilities.py                       |   21 ++-
 src/orca/scripts/apps/Eclipse/script.py            |    6 +-
 src/orca/scripts/apps/Thunderbird/script.py        |   53 ++---
 src/orca/scripts/apps/acroread/script.py           |   11 +-
 src/orca/scripts/apps/evolution/script.py          |   82 ++++----
 src/orca/scripts/apps/gcalctool/script.py          |   17 +-
 src/orca/scripts/apps/gedit/script.py              |   18 +-
 src/orca/scripts/apps/gnome-terminal/script.py     |   24 +--
 src/orca/scripts/apps/packagemanager/script.py     |   13 +-
 src/orca/scripts/apps/pidgin/script.py             |    6 +-
 src/orca/scripts/apps/soffice/script.py            |   38 ++---
 src/orca/scripts/toolkits/Gecko/script.py          |    5 +-
 .../scripts/toolkits/J2SE-access-bridge/script.py  |   11 +-
 src/orca/speech_generator.py                       |    6 +-
 16 files changed, 214 insertions(+), 328 deletions(-)
---
diff --git a/src/orca/chat.py b/src/orca/chat.py
index c8c065c..274e717 100644
--- a/src/orca/chat.py
+++ b/src/orca/chat.py
@@ -972,10 +972,8 @@ class Chat:
         - event: the accessible event being examined
         """
 
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent \
-           and (orca_state.lastNonModifierKeyEvent.event_string == "Tab") \
-           and event.any_data and (event.any_data != "\t"):
+        lastKey, mods = self._script.utilities.lastKeyAndModifiers()
+        if lastKey == "Tab" and event.any_data and event.any_data != "\t":
             return True
 
         return False
diff --git a/src/orca/default.py b/src/orca/default.py
index b732e90..b1fe627 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -1446,11 +1446,8 @@ class Script(script.Script):
         # for example.
         #
         if obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
-            if orca_state.lastNonModifierKeyEvent \
-               and orca_state.lastNonModifierKeyEvent.event_string \
-                   in [" ", "space"]:
-                pass
-            else:
+            eventStr, mods = self.utilities.lastKeyAndModifiers()
+            if not eventStr in [" ", "space"]:
                 return
 
         if event:
@@ -3154,54 +3151,45 @@ class Script(script.Script):
             # user know the selection state.
             # See bugs #486908 and #519564 for more details.
             #
-            if isinstance(orca_state.lastInputEvent,
-                          input_event.KeyboardEvent):
-                if orca_state.lastNonModifierKeyEvent:
-                    keyString = orca_state.lastNonModifierKeyEvent.event_string
-                else:
-                    keyString = None
-                mods = orca_state.lastInputEvent.modifiers
-                isControlKey = mods & settings.CTRL_MODIFIER_MASK
-                state = orca_state.locusOfFocus.getState()
-                announceState = False
-
-                if state.contains(pyatspi.STATE_FOCUSED) and \
-                   self.utilities.isSameObject(
-                    event.source, orca_state.locusOfFocus):
-
-                    if keyString == "space":
-                        if isControlKey:
-                            announceState = True
-                        else:
-                            # 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.
-                            #
-                            eventState = event.source.getState()
-                            selected = eventState.contains(\
-                                           pyatspi.STATE_SELECTED)
-                            announceState = (selected and event.detail1)
-
-                    if (keyString == "Down" or keyString == "Up") \
-                       and event.source.getRole() == pyatspi.ROLE_TABLE_CELL \
-                       and state.contains(pyatspi.STATE_SELECTED):
-                        announceState = True
+            announceState = False
+            keyString, mods = self.utilities.lastKeyAndModifiers()
+            state = orca_state.locusOfFocus.getState()
+            if state.contains(pyatspi.STATE_FOCUSED) \
+               and self.utilities.isSameObject(
+                event.source, orca_state.locusOfFocus):
 
-                if announceState:
-                    if event.detail1:
-                        # Translators: this object is now selected.
-                        # Let the user know this.
-                        #
-                        #
-                        speech.speak(C_("text", "selected"), None, False)
+                if keyString == "space":
+                    if mods & settings.CTRL_MODIFIER_MASK:
+                        announceState = True
                     else:
-                        # Translators: this object is now unselected.
-                        # Let the user know this.
+                        # 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.
                         #
-                        #
-                        speech.speak(C_("text", "unselected"), None, False)
-                    return
+                        eventState = event.source.getState()
+                        selected = eventState.contains(pyatspi.STATE_SELECTED)
+                        announceState = (selected and event.detail1)
+
+                elif keyString in ["Down", "Up"] \
+                     and event.source.getRole() == pyatspi.ROLE_TABLE_CELL \
+                     and state.contains(pyatspi.STATE_SELECTED):
+                    announceState = True
+
+            if announceState:
+                if event.detail1:
+                    # Translators: this object is now selected.
+                    # Let the user know this.
+                    #
+                    #
+                    speech.speak(C_("text", "selected"), None, False)
+                else:
+                    # Translators: this object is now unselected.
+                    # Let the user know this.
+                    #
+                    #
+                    speech.speak(C_("text", "unselected"), None, False)
+                return
 
         if event.type.startswith("object:state-changed:focused"):
             iconified = False
@@ -3230,18 +3218,15 @@ class Script(script.Script):
             if event.type.startswith("object:state-changed:showing"):
                 if event.detail1 == 1:
                     self.presentToolTip(obj)
-                elif orca_state.locusOfFocus \
-                    and isinstance(orca_state.lastInputEvent,
-                                   input_event.KeyboardEvent) \
-                    and orca_state.lastNonModifierKeyEvent \
-                    and (orca_state.lastNonModifierKeyEvent.event_string \
-                         == "F1"):
-                    self.updateBraille(orca_state.locusOfFocus)
-                    utterances = self.speechGenerator.generateSpeech(
-                        orca_state.locusOfFocus)
-                    utterances.extend(self.tutorialGenerator.getTutorial(
-                                      orca_state.locusOfFocus, False))
-                    speech.speak(utterances)
+                elif orca_state.locusOfFocus:
+                    keyString, mods = self.utilities.lastKeyAndModifiers()
+                    if keyString == "F1":
+                        self.updateBraille(orca_state.locusOfFocus)
+                        utterances = self.speechGenerator.generateSpeech(
+                            orca_state.locusOfFocus)
+                        utterances.extend(self.tutorialGenerator.getTutorial(
+                            orca_state.locusOfFocus, False))
+                        speech.speak(utterances)
             return
 
         if event.source.getRole() in state_change_notifiers:
@@ -3336,31 +3321,24 @@ class Script(script.Script):
         # about the ramifications of this when it comes to editors such
         # as vi or emacs.
         #
-        if (not orca_state.lastInputEvent) \
-            or \
-            (not isinstance(orca_state.lastInputEvent,
-                            input_event.KeyboardEvent)):
+        keyString, mods = self.utilities.lastKeyAndModifiers()
+        if not keyString:
             return
 
-        keyString = orca_state.lastNonModifierKeyEvent.event_string
-        controlPressed = orca_state.lastInputEvent.modifiers \
-                         & settings.CTRL_MODIFIER_MASK
         text = event.source.queryText()
         if keyString == "BackSpace":
             # Speak the character that has just been deleted.
             #
             character = event.any_data
 
-        elif (keyString == "Delete") \
-             or (keyString == "D" and controlPressed):
+        elif keyString == "Delete" \
+             or (keyString == "D" and mods & settings.CTRL_MODIFIER_MASK):
             # Speak the character to the right of the caret after
             # the current right character has been deleted.
             #
             offset = text.caretOffset
             [character, startOffset, endOffset] = \
-                text.getTextAtOffset(
-                    offset,
-                    pyatspi.TEXT_BOUNDARY_CHAR)
+                text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
 
         else:
             return
@@ -3404,18 +3382,13 @@ class Script(script.Script):
 
         self.updateBraille(event.source)
 
-        text = event.any_data
-
-        # If this is a spin button, then speak the text and return.
-        #
         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
-            # buttons. See bug #520395 for more details.
+            # We cannot use the event.any_data due to a problem with
+            # selected text in spin buttons. See bug #520395 for more
+            # details.
             #
-            [spinValue, caretOffset, startOffset] = \
-                self.getTextLineAtCaret(event.source)
-            speech.speak(spinValue)
+            [value, caret, start] = self.getTextLineAtCaret(event.source)
+            speech.speak(value)
             return
 
         # If the last input event was a keyboard event, check to see if
@@ -3433,62 +3406,50 @@ class Script(script.Script):
         # comes across as "space" in the keyboard event and " " in the
         # text event.
         #
+        string = event.any_data
         speakThis = False
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-            keyString = orca_state.lastNonModifierKeyEvent.event_string
-            wasAutoComplete = (event.source.getRole() == pyatspi.ROLE_TEXT and \
-                               event.source.queryText().getNSelections())
-            wasCommand = orca_state.lastInputEvent.modifiers \
-                         & settings.COMMAND_MODIFIER_MASK
-            if (text == " " and keyString == "space") \
-                or (text == keyString):
+        if isinstance(orca_state.lastInputEvent, input_event.MouseButtonEvent) \
+           and orca_state.lastInputEvent.button == "2":
+            speakThis = True
+
+        else:
+            keyString, mods = self.utilities.lastKeyAndModifiers()
+            wasCommand = mods & settings.COMMAND_MODIFIER_MASK
+            wasAutoComplete = (event.source.getRole() == pyatspi.ROLE_TEXT \
+                               and event.source.queryText().getNSelections())
+
+            if (string == " " and keyString == "space") or string == keyString:
                 pass
             elif wasCommand or wasAutoComplete:
                 speakThis = True
-            elif (event.source.getRole() == pyatspi.ROLE_PASSWORD_TEXT) and \
-                 settings.enableKeyEcho and settings.enablePrintableKeys:
+            elif event.source.getRole() == pyatspi.ROLE_PASSWORD_TEXT \
+                 and settings.enableKeyEcho and settings.enablePrintableKeys:
                 # Echoing "star" is preferable to echoing the descriptive
                 # name of the bullet that has appeared (e.g. "black circle")
                 #
-                text = "*"
+                string = "*"
                 speakThis = True
 
-        elif isinstance(orca_state.lastInputEvent, \
-                        input_event.MouseButtonEvent) and \
-             orca_state.lastInputEvent.button == "2":
-            speakThis = True
-
         # We might need to echo this if it is a single character.
         #
         speakThis = speakThis \
                     or (settings.enableEchoByCharacter \
-                        and text \
+                        and string \
                         and event.source.getRole() \
                             != pyatspi.ROLE_PASSWORD_TEXT \
-                        and len(text.decode("UTF-8")) == 1)
+                        and len(string.decode("UTF-8")) == 1)
 
         if speakThis:
-            if text.decode("UTF-8").isupper():
-                speech.speak(text, self.voices[settings.UPPERCASE_VOICE])
+            if string.decode("UTF-8").isupper():
+                speech.speak(string, self.voices[settings.UPPERCASE_VOICE])
             else:
-                speech.speak(text)
+                speech.speak(string)
 
         try:
             text = event.source.queryText()
         except NotImplementedError:
             return
 
-        # Pylint is confused and flags this and similar lines, with the
-        # following error:
-        #
-        # E1103:3673:Script.onTextInserted: Instance of 'str' has no
-        #'caretOffset' member (but some types could not be inferred)
-        #
-        # But it does, so we'll just tell pylint that we know what we
-        # are doing.
-        #
-        # pylint: disable-msg=E1103
-
         offset = min(event.detail1, text.caretOffset - 1)
         previousOffset = offset - 1
         if (offset < 0 or previousOffset < 0):
@@ -3735,18 +3696,15 @@ class Script(script.Script):
         # down is done via other actions such as "i" or "j".  We may
         # need to think about this a little harder.]]]
         #
-        if not isinstance(orca_state.lastInputEvent,
-                          input_event.KeyboardEvent):
+        keyString, mods = self.utilities.lastKeyAndModifiers()
+        if not keyString:
             return
-
-        keyString = orca_state.lastNonModifierKeyEvent.event_string
-        mods = orca_state.lastInputEvent.modifiers
         isControlKey = mods & settings.CTRL_MODIFIER_MASK
         isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
         lastPos = self.pointOfReference.get("lastCursorPosition")
         hasLastPos = (lastPos != None)
 
-        if (keyString == "Up") or (keyString == "Down"):
+        if keyString in ["Up", "Down"]:
             # If the user has typed Shift-Up or Shift-Down, then we want
             # to speak the text that has just been selected or unselected,
             # otherwise we speak the new line where the text cursor is
@@ -3790,7 +3748,7 @@ class Script(script.Script):
                 [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
                 self.sayLine(obj)
 
-        elif (keyString == "Left") or (keyString == "Right"):
+        elif keyString in ["Left", "Right"]:
             # If the user has typed Control-Shift-Up or Control-Shift-Dowm,
             # then we want to speak the text that has just been selected
             # or unselected, otherwise if the user has typed Control-Left
@@ -3843,7 +3801,7 @@ class Script(script.Script):
                 [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
                 self.sayLine(obj)
 
-        elif (keyString == "Home") or (keyString == "End"):
+        elif keyString in ["Home", "End"]:
             # If the user has typed Shift-Home or Shift-End, then we want
             # to speak the text that has just been selected or unselected,
             # otherwise if the user has typed Control-Home or Control-End,
@@ -4333,13 +4291,7 @@ class Script(script.Script):
         # right, then speak the character to the left of where the text
         # caret is (i.e. the selected character).
         #
-        try:
-            mods = orca_state.lastInputEvent.modifiers
-            eventString = orca_state.lastInputEvent.event_string
-        except:
-            mods = 0
-            eventString = ""
-
+        eventString, mods = self.utilities.lastKeyAndModifiers()
         if (mods & settings.SHIFT_MODIFIER_MASK) \
            and eventString in ["Right", "Down"]:
             offset -= 1
@@ -4461,7 +4413,7 @@ class Script(script.Script):
 
         text = obj.queryText()
         offset = text.caretOffset
-        lastKey = orca_state.lastNonModifierKeyEvent.event_string
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
         lastWord = orca_state.lastWord
 
         [word, startOffset, endOffset] = \
@@ -5102,14 +5054,7 @@ class Script(script.Script):
         # where <state> is either "selected" or "unselected" depending
         # upon whether there are any text selections.
         #
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent:
-            eventStr = orca_state.lastNonModifierKeyEvent.event_string
-            mods = orca_state.lastInputEvent.modifiers
-        else:
-            eventStr = None
-            mods = 0
-
+        eventStr, mods = self.utilities.lastKeyAndModifiers()
         isControlKey = mods & settings.CTRL_MODIFIER_MASK
         isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
         selectedText = (text.getNSelections() != 0)
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index 56819c4..c687072 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -33,6 +33,7 @@ import pyatspi
 import re
 
 import debug
+import input_event
 import mouse_review
 import orca_state
 import settings
@@ -1849,8 +1850,8 @@ class Utilities:
         except:
             return [0, 0]
 
-        if orca_state.lastInputEvent.modifiers & settings.SHIFT_MODIFIER_MASK \
-           and orca_state.lastNonModifierKeyEvent.event_string == "Right":
+        lastKey, mods = self.lastKeyAndModifiers()
+        if mods & settings.SHIFT_MODIFIER_MASK and lastKey == "Right":
             startOffset = text.caretOffset - 1
             endOffset = text.caretOffset
         else:
@@ -2552,6 +2553,22 @@ class Utilities:
 
         return False
 
+    @staticmethod
+    def lastKeyAndModifiers():
+        """Convenience method which returns a tuple containing the event
+        string and modifiers of the last non-modifier key event or ("", 0)
+        if there is no such event."""
+
+        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
+           and orca_state.lastNonModifierKeyEvent:
+            eventStr = orca_state.lastNonModifierKeyEvent.event_string
+            mods = orca_state.lastInputEvent.modifiers
+        else:
+            eventStr = ""
+            mods = 0
+
+        return (eventStr, mods)
+
     def mnemonicShortcutAccelerator(self, obj):
         """Gets the mnemonic, accelerator string and possibly shortcut
         for the given object.  These are based upon the first accessible
diff --git a/src/orca/scripts/apps/Eclipse/script.py b/src/orca/scripts/apps/Eclipse/script.py
index e84c004..f9efde4 100644
--- a/src/orca/scripts/apps/Eclipse/script.py
+++ b/src/orca/scripts/apps/Eclipse/script.py
@@ -26,7 +26,6 @@ __copyright__ = "Copyright (c) 2010 Informal Informatica LTDA."
 __license__   = "LGPL"
 
 import orca.default as default
-import orca.orca_state as orca_state
 import pyatspi
 from script_utilities import Utilities
 
@@ -67,9 +66,8 @@ class Script(default.Script):
         textInserted = self._textInserted
         self._textInserted = False
         # check if the obj was spoken in the default script
-        if orca_state.lastNonModifierKeyEvent \
-                and orca_state.lastNonModifierKeyEvent.event_string in \
-                self.movementKeys:
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        if lastKey in self.movementKeys:
             # already spoken in default script
             return
 
diff --git a/src/orca/scripts/apps/Thunderbird/script.py b/src/orca/scripts/apps/Thunderbird/script.py
index 2086ad3..b5be328 100644
--- a/src/orca/scripts/apps/Thunderbird/script.py
+++ b/src/orca/scripts/apps/Thunderbird/script.py
@@ -31,7 +31,6 @@ import pyatspi
 import orca.orca as orca
 import orca.debug as debug
 import orca.default as default
-import orca.input_event as input_event
 import orca.orca_state as orca_state
 import orca.settings as settings
 import orca.speech as speech
@@ -201,10 +200,8 @@ class Script(Gecko.Script):
         # based on the locusOfFocus other times Gecko is because of the
         # caret context.
         #
-        updatePosition = False
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-            string = orca_state.lastNonModifierKeyEvent.event_string
-            updatePosition = string in ["Page_Up", "Page_Down"]
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        updatePosition = lastKey in ["Page_Up", "Page_Down"]
 
         # Unlike the unpredictable wild, wild web, odds are good that a
         # caret-moved event in a message composition window is valid. But
@@ -399,11 +396,9 @@ class Script(Gecko.Script):
                      pyatspi.ROLE_SCROLL_PANE,
                      pyatspi.ROLE_SCROLL_PANE]
         if self.utilities.hasMatchingHierarchy(event.source, rolesList):
-            if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent)\
-               and orca_state.lastNonModifierKeyEvent:
-                string = orca_state.lastNonModifierKeyEvent.event_string
-                if string == "Delete":
-                    oldLocusOfFocus = None
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
+            if lastKey == "Delete":
+                oldLocusOfFocus = None
 
         # If the user has just deleted an open mail message, then we want to
         # try to speak the new name of the open mail message frame.
@@ -414,13 +409,12 @@ class Script(Gecko.Script):
                      pyatspi.ROLE_FRAME, \
                      pyatspi.ROLE_APPLICATION]
         if self.utilities.hasMatchingHierarchy(event.source, rolesList):
-            if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-                string = orca_state.lastNonModifierKeyEvent.event_string
-                if string == "Delete":
-                    oldLocusOfFocus = None
-                    state = newLocusOfFocus.getState()
-                    if state.contains(pyatspi.STATE_DEFUNCT):
-                        newLocusOfFocus = event.source
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
+            if lastKey == "Delete":
+                oldLocusOfFocus = None
+                state = newLocusOfFocus.getState()
+                if state.contains(pyatspi.STATE_DEFUNCT):
+                    newLocusOfFocus = event.source
 
         # Pass the event onto the parent class to be handled in the default way.
 
@@ -517,18 +511,17 @@ class Script(Gecko.Script):
         # we do when a new message window is opened. See bug #540039 for more
         # details.
         #
-        rolesList = [pyatspi.ROLE_DOCUMENT_FRAME, \
-                     pyatspi.ROLE_INTERNAL_FRAME, \
-                     pyatspi.ROLE_FRAME, \
+        rolesList = [pyatspi.ROLE_DOCUMENT_FRAME,
+                     pyatspi.ROLE_INTERNAL_FRAME,
+                     pyatspi.ROLE_FRAME,
                      pyatspi.ROLE_APPLICATION]
         if self.utilities.hasMatchingHierarchy(event.source, rolesList):
-            if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-                string = orca_state.lastNonModifierKeyEvent.event_string
-                if string == "Delete":
-                    speech.speak(obj.name)
-                    [obj, offset] = self.findFirstCaretContext(obj, 0)
-                    self.setCaretPosition(obj, offset)
-                    return
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
+            if lastKey == "Delete":
+                speech.speak(obj.name)
+                [obj, offset] = self.findFirstCaretContext(obj, 0)
+                self.setCaretPosition(obj, offset)
+                return
 
         # If we get a "object:property-change:accessible-name" event for 
         # the first item in the Suggestions lists for the spell checking
@@ -536,9 +529,9 @@ class Script(Gecko.Script):
         # will by the "Misspelled word:" label and the currently misspelled
         # word. See bug #535192 for more details.
         #
-        rolesList = [pyatspi.ROLE_LIST_ITEM, \
-                     pyatspi.ROLE_LIST, \
-                     pyatspi.ROLE_DIALOG, \
+        rolesList = [pyatspi.ROLE_LIST_ITEM,
+                     pyatspi.ROLE_LIST,
+                     pyatspi.ROLE_DIALOG,
                      pyatspi.ROLE_APPLICATION]
         if self.utilities.hasMatchingHierarchy(obj, rolesList):
             dialog = obj.parent.parent
diff --git a/src/orca/scripts/apps/acroread/script.py b/src/orca/scripts/apps/acroread/script.py
index ff87af0..cde9df0 100644
--- a/src/orca/scripts/apps/acroread/script.py
+++ b/src/orca/scripts/apps/acroread/script.py
@@ -385,11 +385,7 @@ class Script(default.Script):
             # to the default script.
             #
             debug.println(self.debugLevel, "acroread: Drawing area bug")
-            lastKey = None
-            try:
-                lastKey = orca_state.lastNonModifierKeyEvent.event_string
-            except:
-                pass
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
             locusOfFocusIndex = orca_state.locusOfFocus.getIndexInParent()
             childIndex = None
 
@@ -493,7 +489,7 @@ class Script(default.Script):
         """
 
         lastInputEvent = orca_state.lastInputEvent
-        lastKey = lastInputEvent.event_string
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
 
         # A single keypress usually results in multiple, not necessarily
         # identical, caret-moved events.  Check to see if the events are
@@ -650,8 +646,7 @@ class Script(default.Script):
         else:
             text = obj.queryText()
             offset = text.caretOffset
-            lastKey = orca_state.lastNonModifierKeyEvent.event_string
-
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
             if lastKey == "Right":
                 penultimateWord = orca_state.lastWord
                 [lastWord, startOffset, endOffset] = \
diff --git a/src/orca/scripts/apps/evolution/script.py b/src/orca/scripts/apps/evolution/script.py
index 7561af2..75f394b 100644
--- a/src/orca/scripts/apps/evolution/script.py
+++ b/src/orca/scripts/apps/evolution/script.py
@@ -423,11 +423,9 @@ class Script(default.Script):
             # changed, then speak all the table cells.
             #
             justDeleted = False
-            if isinstance(orca_state.lastInputEvent,
-                          input_event.KeyboardEvent):
-                string = orca_state.lastNonModifierKeyEvent.event_string
-                if string == "Delete":
-                    justDeleted = True
+            string, mods = self.utilities.lastKeyAndModifiers()
+            if string == "Delete":
+                justDeleted = True
 
             speakAll = (self.lastMessageRow != row) or \
                        ((row == 0 or row == parentTable.nRows-1) and \
@@ -879,26 +877,24 @@ class Script(default.Script):
             # 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):
-                if self.utilities.isSameObject(event.source.parent,
-                                     orca_state.locusOfFocus.parent):
-                    lastKey = orca_state.lastNonModifierKeyEvent.event_string
-                    if self.utilities.isMessageBody(orca_state.locusOfFocus) \
-                       and lastKey not in ["Left", "Right", "Up", "Down",
-                                           "Home", "End", "Return", "Tab"]:
-                        return
+            if self.utilities.isSameObject(event.source.parent,
+                                           orca_state.locusOfFocus.parent):
+                lastKey, mods = self.utilities.lastKeyAndModifiers()
+                if self.utilities.isMessageBody(orca_state.locusOfFocus) \
+                   and lastKey not in ["Left", "Right", "Up", "Down",
+                                       "Home", "End", "Return", "Tab"]:
+                    return
 
-                    # If the last keyboard event was a "same line"
-                    # navigation key, then pass this event onto the
-                    # onCaretMoved() method in the parent class for
-                    # speaking. See bug #516565 for more details.
-                    #
-                    if lastKey in ["Left", "Right", "Home", "End"]:
-                        default.Script.onCaretMoved(self, event)
-                        return
+                # If the last keyboard event was a "same line"
+                # navigation key, then pass this event onto the
+                # onCaretMoved() method in the parent class for
+                # speaking. See bug #516565 for more details.
+                #
+                if lastKey in ["Left", "Right", "Home", "End"]:
+                    default.Script.onCaretMoved(self, event)
+                    return
 
             self.message_panel = event.source.parent.parent
-
             self.presentMessageLine(event.source, newLocusOfFocus)
             return
 
@@ -1035,28 +1031,24 @@ class Script(default.Script):
         # prior to speaking the actual message that gets focus.
         # See bug #347964.
         #
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent:
-            string = orca_state.lastNonModifierKeyEvent.event_string
-            if string == "Delete":
-                rolesList = [pyatspi.ROLE_TABLE_CELL,
-                             pyatspi.ROLE_TREE_TABLE,
-                             pyatspi.ROLE_UNKNOWN,
-                             pyatspi.ROLE_SCROLL_PANE]
-                oldLocusOfFocus = orca_state.locusOfFocus
-                if self.utilities.hasMatchingHierarchy(
-                        event.source, rolesList) \
-                   and self.utilities.hasMatchingHierarchy(
-                        oldLocusOfFocus, rolesList):
-                    parent = event.source.parent
-                    parentTable = parent.queryTable()
-                    newIndex = self.utilities.cellIndex(event.source)
-                    newRow = parentTable.getRowAtIndex(newIndex)
-                    oldIndex = self.utilities.cellIndex(oldLocusOfFocus)
-                    oldRow = parentTable.getRowAtIndex(oldIndex)
-                    nRows = parentTable.nRows
-                    if (newRow != oldRow) and (oldRow != nRows):
-                        return
+        string, mods = self.utilities.lastKeyAndModifiers()
+        if string == "Delete":
+            roles = [pyatspi.ROLE_TABLE_CELL,
+                     pyatspi.ROLE_TREE_TABLE,
+                     pyatspi.ROLE_UNKNOWN,
+                     pyatspi.ROLE_SCROLL_PANE]
+            oldLocusOfFocus = orca_state.locusOfFocus
+            if self.utilities.hasMatchingHierarchy(event.source, roles) \
+               and self.utilities.hasMatchingHierarchy(oldLocusOfFocus, roles):
+                parent = event.source.parent
+                parentTable = parent.queryTable()
+                newIndex = self.utilities.cellIndex(event.source)
+                newRow = parentTable.getRowAtIndex(newIndex)
+                oldIndex = self.utilities.cellIndex(oldLocusOfFocus)
+                oldRow = parentTable.getRowAtIndex(oldIndex)
+                nRows = parentTable.nRows
+                if (newRow != oldRow) and (oldRow != nRows):
+                    return
 
         # For everything else, pass the event onto the parent class
         # to be handled in the default way.
diff --git a/src/orca/scripts/apps/gcalctool/script.py b/src/orca/scripts/apps/gcalctool/script.py
index 398500f..1e10e16 100644
--- a/src/orca/scripts/apps/gcalctool/script.py
+++ b/src/orca/scripts/apps/gcalctool/script.py
@@ -125,18 +125,8 @@ class Script(default.Script):
         if self.utilities.isSameObject(event.source, self._resultsDisplay):
             contents = self.utilities.substring(self._resultsDisplay, 0, -1)
             self.displayBrailleMessage(contents)
-
-            if (orca_state.lastInputEvent is None) \
-                   or \
-                   (not isinstance(orca_state.lastInputEvent,
-                                   input_event.KeyboardEvent)):
-                return
-
-            if (orca_state.lastNonModifierKeyEvent.event_string == "space") \
-                   or (orca_state.lastNonModifierKeyEvent.event_string \
-                       == "Return") \
-                   or (orca_state.lastNonModifierKeyEvent.event_string == "="):
-
+            lastKey, mods = self.utilities.lastKeyAndModifiers()
+            if lastKey in ["space", "Return", "="]:
                 # gcalctool issues several identical text inserted events
                 # for a single press of keys such as enter, space, or equals.
                 # In fact, it's usually about 4, but we cannot depend upon
@@ -184,6 +174,9 @@ class Script(default.Script):
                     speech.speak(contents)
                     self._lastSpokenContents = contents
 
+            if not lastKey:
+                return
+
             self._lastProcessedKeyEvent = \
                 input_event.KeyboardEvent(orca_state.lastNonModifierKeyEvent)
 
diff --git a/src/orca/scripts/apps/gedit/script.py b/src/orca/scripts/apps/gedit/script.py
index 73977a5..5281760 100644
--- a/src/orca/scripts/apps/gedit/script.py
+++ b/src/orca/scripts/apps/gedit/script.py
@@ -29,7 +29,6 @@ import pyatspi
 
 import orca.debug as debug
 import orca.default as default
-import orca.input_event as input_event
 import orca.orca as orca
 import orca.orca_state as orca_state
 import orca.settings as settings
@@ -489,6 +488,8 @@ class Script(default.Script):
         # apparently get two identical "object:property-change:accessible-name"
         # events.]]]
 
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+
         # Translators: the "Phrase not found" is the result of a failed
         # find command.  It must be the same as what gedit uses.  We hate
         # keying off stuff like this, but we're forced to do so in this
@@ -496,12 +497,10 @@ class Script(default.Script):
         #
         if event.source.getRole() == pyatspi.ROLE_STATUS_BAR \
            and self.isFocusOnFindDialog() \
-           and orca_state.lastNonModifierKeyEvent \
-           and orca_state.lastNonModifierKeyEvent.event_string == "Return" \
+           and lastKey == "Return" \
            and event.source.name == _("Phrase not found"):
             debug.println(self.debugLevel,
                           "gedit.onNameChanged - phrase not found.")
-
             speech.speak(event.source.name)
 
         # Pass the event onto the parent class to be handled in the default way.
@@ -551,9 +550,8 @@ class Script(default.Script):
         # then speak the current text line, to give an indication of what
         # we've just found.
         #
-        if self.isFocusOnFindDialog() \
-           and orca_state.lastNonModifierKeyEvent \
-           and orca_state.lastNonModifierKeyEvent.event_string == "Return":
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        if self.isFocusOnFindDialog() and lastKey == "Return":
             debug.println(self.debugLevel, "gedit.onCaretMoved - find dialog.")
             allComboBoxes = self.utilities.descendantsWithRole(
                 orca_state.locusOfFocus.getApplication(),
@@ -573,11 +571,7 @@ class Script(default.Script):
         # If Ctrl+G was used to repeat a find command, speak the line that
         # the caret moved to.
         #
-        if orca_state.lastInputEvent \
-           and isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent)\
-           and orca_state.lastInputEvent.event_string == 'G' \
-           and orca_state.lastInputEvent.modifiers \
-               & (1 << pyatspi.MODIFIER_CONTROL):
+        if lastKey == 'G' and mods & settings.CTRL_MODIFIER_MASK:
             self.sayLine(event.source)
 
         # For everything else, pass the caret moved event onto the parent
diff --git a/src/orca/scripts/apps/gnome-terminal/script.py b/src/orca/scripts/apps/gnome-terminal/script.py
index 057f054..53696e5 100644
--- a/src/orca/scripts/apps/gnome-terminal/script.py
+++ b/src/orca/scripts/apps/gnome-terminal/script.py
@@ -127,11 +127,7 @@ class Script(default.Script):
         - event: the Event
         """
 
-        if orca_state.lastInputEvent and orca_state.lastNonModifierKeyEvent \
-           and isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-            event_string = orca_state.lastNonModifierKeyEvent.event_string
-        else:
-            event_string = None
+        event_string, mods = self.utilities.lastKeyAndModifiers()
 
         # We only do special things when people press backspace
         # in terminals.
@@ -204,12 +200,9 @@ class Script(default.Script):
         matchFound = False
         speakThis = False
         if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
-            keyString = orca_state.lastNonModifierKeyEvent.event_string
-
-            controlPressed = orca_state.lastInputEvent.modifiers \
-                             & settings.CTRL_MODIFIER_MASK
-
-            if (keyString == "Delete") or (keyString == "BackSpace"):
+            keyString, mods = self.utilities.lastKeyAndModifiers()
+            controlPressed = mods & settings.CTRL_MODIFIER_MASK
+            if keyString in ["Delete", "BackSpace"]:
                 return
             elif (keyString == "D") and controlPressed:
                 text = text.decode("UTF-8")[0].decode("UTF-8")
@@ -238,13 +231,8 @@ class Script(default.Script):
             # us a string typically longer than what the length of a
             # compressed string is (we choose 5 here), then output that.
             #
-            wasCommand = orca_state.lastInputEvent.modifiers \
-                         & settings.COMMAND_MODIFIER_MASK
-            wasCommand = wasCommand \
-                         or (keyString == "Return") \
-                         or (keyString == "Tab")
-            if (text == " " and keyString == "space") \
-                or (text == keyString):
+            wasCommand = controlPressed or keyString in ["Return", "Tab"]
+            if (text == " " and keyString == "space") or text == keyString:
                 matchFound = True
             elif wasCommand or (len(text) > 5):
                 speakThis = True
diff --git a/src/orca/scripts/apps/packagemanager/script.py b/src/orca/scripts/apps/packagemanager/script.py
index c79e6fb..0b247f0 100644
--- a/src/orca/scripts/apps/packagemanager/script.py
+++ b/src/orca/scripts/apps/packagemanager/script.py
@@ -31,7 +31,6 @@ import gtk
 import pyatspi
 
 import orca.default as default
-import orca.input_event as input_event
 import orca.orca as orca
 import orca.orca_state as orca_state
 import orca.settings as settings
@@ -151,10 +150,8 @@ class Script(default.Script):
 
         # Prevent chattiness when arrowing out of or into a link.
         #
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent \
-           and orca_state.lastNonModifierKeyEvent.event_string in \
-               ["Left", "Right", "Up", "Down"] \
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        if lastKey in ["Left", "Right", "Up", "Down"] \
            and event and event.type.startswith("focus:") \
            and (self.utilities.isLink(oldLocusOfFocus) \
            or self.utilities.isLink(newLocusOfFocus)):
@@ -434,10 +431,8 @@ class Script(default.Script):
         except:
             return
 
-        if text.caretOffset == text.characterCount \
-           and isinstance(orca_state.lastInputEvent,
-                          input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent.event_string == "Right":
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        if text.caretOffset == text.characterCount and lastKey == "Right":
             nextObj = self.getRelationTarget(obj, pyatspi.RELATION_FLOWS_TO)
             if nextObj and nextObj.getRole() == pyatspi.ROLE_TEXT:
                 obj = nextObj
diff --git a/src/orca/scripts/apps/pidgin/script.py b/src/orca/scripts/apps/pidgin/script.py
index 03b7e41..ce2a675 100644
--- a/src/orca/scripts/apps/pidgin/script.py
+++ b/src/orca/scripts/apps/pidgin/script.py
@@ -753,6 +753,7 @@ class Script(default.Script):
                 self.chatRoomMessages[chatRoomName].append("")
                 i += 1
 
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
         if event.source and (event.source == chatArea):
             # We always automatically go back to focus tracking mode when
             # someone sends us a message.
@@ -809,10 +810,7 @@ class Script(default.Script):
 
                 self.chatRoomMessages[chatRoomName].append(message)
 
-        elif isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-             and orca_state.lastNonModifierKeyEvent \
-             and (orca_state.lastNonModifierKeyEvent.event_string == "Tab") \
-             and event.any_data and (event.any_data != "\t"):
+        elif lastKey == "Tab" and event.any_data and event.any_data != "\t":
             # This is autocompleted text (the name of a user in an IRC
             # chatroom).  The default script isn't announcing it because
             # it's not selected.
diff --git a/src/orca/scripts/apps/soffice/script.py b/src/orca/scripts/apps/soffice/script.py
index 37d97c8..082fc78 100644
--- a/src/orca/scripts/apps/soffice/script.py
+++ b/src/orca/scripts/apps/soffice/script.py
@@ -1730,9 +1730,8 @@ class Script(default.Script):
         # spoken. So we'll speak them before sending this event off to the
         # default script.
         #
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent \
-           and orca_state.lastNonModifierKeyEvent.event_string == "Return" \
+        lastKey, mods = self.utilities.lastKeyAndModifiers()
+        if lastKey == "Return" \
            and event.source.getRole() == pyatspi.ROLE_PARAGRAPH:
             try:
                 charCount = event.source.queryText().characterCount
@@ -1888,13 +1887,11 @@ class Script(default.Script):
                 y = orca_state.lastInputEvent.y
                 weToggledIt = event.source.queryComponent().contains(x, y, 0)
 
-            elif isinstance(orca_state.lastInputEvent, \
-                            input_event.KeyboardEvent):
-                keyString = orca_state.lastNonModifierKeyEvent.event_string
+            else:
+                keyString, mods = self.utilities.lastKeyAndModifiers()
                 navKeys = ["Up", "Down", "Left", "Right", "Page_Up",
                            "Page_Down", "Home", "End"]
-                wasCommand = orca_state.lastInputEvent.modifiers \
-                             & settings.COMMAND_MODIFIER_MASK
+                wasCommand = mods & settings.COMMAND_MODIFIER_MASK
                 weToggledIt = wasCommand and keyString not in navKeys
 
             if weToggledIt:
@@ -2074,16 +2071,13 @@ class Script(default.Script):
             if settings.enableEchoByWord and \
                (self.utilities.hasMatchingHierarchy(event.source, rolesList) or
                 self.utilities.hasMatchingHierarchy(event.source, rolesList1)):
-                if isinstance(orca_state.lastInputEvent,
-                              input_event.KeyboardEvent):
-                    keyString = orca_state.lastNonModifierKeyEvent.event_string
-                    focusRole = orca_state.locusOfFocus.getRole()
-                    if focusRole != pyatspi.ROLE_UNKNOWN and \
-                       keyString == "Return":
-                        result = self.utilities.substring(event.source, 0, -1)
-                        line = result.decode("UTF-8")
-                        self.echoPreviousWord(event.source, len(line))
-                        return
+                keyString, mods = self.utilities.lastKeyAndModifiers()
+                focusRole = orca_state.locusOfFocus.getRole()
+                if focusRole != pyatspi.ROLE_UNKNOWN and keyString == "Return":
+                    result = self.utilities.substring(event.source, 0, -1)
+                    line = result.decode("UTF-8")
+                    self.echoPreviousWord(event.source, len(line))
+                    return
 
         # Otherwise, if the object is losing focus, then just ignore this event.
         #
@@ -2103,13 +2097,7 @@ class Script(default.Script):
                 #
                 self.lastCell[1] = event.detail1
 
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent:
-            event_string = orca_state.lastNonModifierKeyEvent.event_string
-            mods = orca_state.lastInputEvent.modifiers
-        else:
-            event_string = ''
-            mods = 0
+        event_string, mods = self.utilities.lastKeyAndModifiers()
         isControlKey = mods & settings.CTRL_MODIFIER_MASK
         isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
 
diff --git a/src/orca/scripts/toolkits/Gecko/script.py b/src/orca/scripts/toolkits/Gecko/script.py
index 481ba0a..650e94f 100644
--- a/src/orca/scripts/toolkits/Gecko/script.py
+++ b/src/orca/scripts/toolkits/Gecko/script.py
@@ -1270,9 +1270,8 @@ class Script(default.Script):
            and self.utilities.isSameObject(obj, event.source):
             return
 
-        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent) \
-           and orca_state.lastNonModifierKeyEvent:
-            string = orca_state.lastNonModifierKeyEvent.event_string
+        if isinstance(orca_state.lastInputEvent, input_event.KeyboardEvent):
+            string, mods = self.utilities.lastKeyAndModifiers()
             if self.useCaretNavigationModel(orca_state.lastInputEvent):
                 # Orca is set to control the caret and is in a place where
                 # doing so is appropriate.  Therefore, this event is likely
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/script.py b/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
index 4406eff..c3ab824 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/script.py
@@ -196,14 +196,9 @@ class Script(default.Script):
                            pyatspi.ROLE_PANEL,
                            pyatspi.ROLE_SPIN_BUTTON])
         if isSpinBox:
-            if isinstance(orca_state.lastInputEvent,
-                          input_event.KeyboardEvent):
-                eventStr = orca_state.lastNonModifierKeyEvent.event_string
-            else:
-                eventStr = None
-            if (eventStr in ["Up", "Down"]) \
-               or isinstance(orca_state.lastInputEvent,
-                             input_event.MouseButtonEvent):
+            eventStr, mods = self.utilities.lastKeyAndModifiers()
+            if eventStr in ["Up", "Down"] or isinstance(
+               orca_state.lastInputEvent, input_event.MouseButtonEvent):
                 return
 
         default.Script.onCaretMoved(self, event)
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 5196601..62bc8fc 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -28,7 +28,6 @@ __license__   = "LGPL"
 import urlparse, urllib2
 
 import generator
-import orca_state
 import pyatspi
 import rolenames
 import settings
@@ -504,9 +503,8 @@ class SpeechGenerator(generator.Generator):
         # moving left or right on the same row, then don't announce the
         # selection state to the user. See bug #523235 for more details.
         #
-        if checkIfSelected and orca_state.lastNonModifierKeyEvent \
-           and orca_state.lastNonModifierKeyEvent.event_string \
-               in ["Left", "Right"]:
+        lastKey, mods = self._script.utilities.lastKeyAndModifiers()
+        if checkIfSelected and lastKey in ["Left", "Right"]:
             checkIfSelected = False
 
         if objRole == pyatspi.ROLE_ICON \



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