[orca] Begin refactoring of keyboard event processing



commit e54b5f2058a3daa83435c991cdec42eadf408793
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Mon Apr 4 18:03:05 2016 -0400

    Begin refactoring of keyboard event processing

 src/orca/event_manager.py         |   33 ++--
 src/orca/input_event.py           |  386 ++++++++++++++++++++++++++++---------
 src/orca/keybindings.py           |   18 --
 src/orca/notification_messages.py |   10 +-
 src/orca/orca.py                  |  119 ++----------
 src/orca/orca_state.py            |    2 +
 src/orca/script.py                |   46 -----
 src/orca/scripts/default.py       |   14 ++-
 src/orca/scripts/self_voicing.py  |   10 -
 9 files changed, 339 insertions(+), 299 deletions(-)
---
diff --git a/src/orca/event_manager.py b/src/orca/event_manager.py
index c2175a2..384f50d 100644
--- a/src/orca/event_manager.py
+++ b/src/orca/event_manager.py
@@ -71,6 +71,7 @@ class EventManager:
         self._registerListener("window:deactivate")
         self._registerListener("object:children-changed")
         self._registerListener("mouse:button")
+        self.registerKeystrokeListener(self._processKeyboardEvent)
         self._active = True
         debug.println(debug.LEVEL_INFO, 'EVENT MANAGER: Activated', True)
 
@@ -82,6 +83,7 @@ class EventManager:
         for eventType in list(self._scriptListenerCounts.keys()):
             self.registry.deregisterEventListener(self._enqueue, eventType)
         self._scriptListenerCounts = {}
+        self.deregisterKeystrokeListener(self._processKeyboardEvent)
         debug.println(debug.LEVEL_INFO, 'EVENT MANAGER: Deactivated', True)
 
     def ignoreEventTypes(self, eventTypeList):
@@ -489,10 +491,7 @@ class EventManager:
         if not orca_state.activeScript:
             return
 
-        if isinstance(event, input_event.KeyboardEvent):
-            function = orca_state.activeScript.processKeyboardEvent
-            data = "'%s' (%d)" % (event.event_string, event.hw_code)
-        elif isinstance(event, input_event.BrailleEvent):
+        if isinstance(event, input_event.BrailleEvent):
             function = orca_state.activeScript.processBrailleEvent
             data = "'%s'" % repr(event.event)
         else:
@@ -681,26 +680,18 @@ class EventManager:
             debug.println(debug.LEVEL_INFO, msg, True)
             debug.printException(debug.LEVEL_INFO)
 
-    def processKeyboardEvent(self, keyboardEvent):
-        """Processes the given keyboard event based on the keybinding from the
-        currently active script. This method is called synchronously from the
-        at-spi registry and should be performant.  In addition, it must return
-        True if it has consumed the event (and False if not).
+    def _processKeyboardEvent(self, event):
+        keyboardEvent = input_event.KeyboardEvent(event)
+        if not keyboardEvent.is_duplicate:
+            debug.println(debug.LEVEL_INFO, "\n%s" % keyboardEvent)
 
-        Arguments:
-        - keyboardEvent: an instance of input_event.KeyboardEvent
-
-        Returns True if the event should be consumed.
-        """
+        rv = keyboardEvent.process()
 
-        consume = False
-        if orca_state.activeScript \
-           and orca_state.activeScript.consumesKeyboardEvent(keyboardEvent):
-            consume = not orca_state.bypassNextCommand
-            if consume:
-                self._enqueue(keyboardEvent)
+        # Do any needed xmodmap crap. Hopefully this can die soon.
+        from orca import orca
+        orca.updateKeyMap(keyboardEvent)
 
-        return consume
+        return rv
 
     def processBrailleEvent(self, brailleEvent):
         """Called whenever a cursor key is pressed on the Braille display.
diff --git a/src/orca/input_event.py b/src/orca/input_event.py
index 74cea40..83fd0c3 100644
--- a/src/orca/input_event.py
+++ b/src/orca/input_event.py
@@ -1,7 +1,7 @@
 # Orca
 #
 # Copyright 2005-2008 Sun Microsystems Inc.
-# Copyright 2011 Igalia, S.L.
+# Copyright 2011-2016 Igalia, S.L.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -24,12 +24,11 @@ __id__        = "$Id$"
 __version__   = "$Revision$"
 __date__      = "$Date$"
 __copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc." \
-                "Copyright (c) 2011 Igalia, S.L."
+                "Copyright (c) 2011-2016 Igalia, S.L."
 __license__   = "LGPL"
 
 import pyatspi
 import time
-import unicodedata
 
 from . import debug
 from . import keybindings
@@ -44,62 +43,28 @@ MOUSE_BUTTON_EVENT = "mouse:button"
 
 class InputEvent:
 
-    _clickCount = 0
-
     def __init__(self, eventType):
-        """Creates a new input event of the given type.
-
-        Arguments:
-        - eventType: one of KEYBOARD_EVENT, BRAILLE_EVENT, MOUSE_BUTTON_EVENT
-        """
+        """Creates a new KEYBOARD_EVENT, BRAILLE_EVENT, or MOUSE_BUTTON_EVENT."""
 
         self.type = eventType
+        self.time = time.time()
+        self._clickCount = 0
 
     def getClickCount(self):
         """Return the count of the number of clicks a user has made."""
 
-        # TODO - JD: I relocated this out of script.py, because it seems
-        # to belong there even less than here. Need to revisit how this
-        # functionality is used and where.
-        return InputEvent._clickCount
+        return self._clickCount
 
     def setClickCount(self):
-        """Sets the count of the number of clicks a user has made to one
-        of the non-modifier keys on the keyboard.  Note that this looks at
-        the event_string (keysym) instead of hw_code (keycode) because
-        the Java platform gives us completely different keycodes for keys.
-
-        Arguments:
-        - inputEvent: the current input event.
-        """
+        """Updates the count of the number of clicks a user has made."""
 
-        # TODO - JD: This setter for the getter I found in script.py was
-        # in orca.py. :-/ Again, this needs sorting out. But for now it
-        # is less out of place here.
-
-        lastInputEvent = orca_state.lastNonModifierKeyEvent
-        if self.type == pyatspi.KEY_RELEASED_EVENT:
-            return
-
-        if not isinstance(self, KeyboardEvent):
-            InputEvent._clickCount = 0
-            return
-
-        if not isinstance(lastInputEvent, KeyboardEvent):
-            InputEvent._clickCount = 1
-            return
-
-        if self.time - lastInputEvent.time < settings.doubleClickTimeout \
-            and lastInputEvent.event_string == self.event_string:
-            # Cap the possible number of clicks at 3.
-            if InputEvent._clickCount < 3:
-                InputEvent._clickCount += 1
-                return
-
-        InputEvent._clickCount = 1
+        pass
 
 class KeyboardEvent(InputEvent):
 
+    duplicateCount = 0
+    orcaModifierPressed = False
+
     TYPE_UNKNOWN          = "unknown"
     TYPE_PRINTABLE        = "printable"
     TYPE_MODIFIER         = "modifier"
@@ -120,29 +85,32 @@ class KeyboardEvent(InputEvent):
         - event: the AT-SPI keyboard event
         """
 
-        InputEvent.__init__(self, KEYBOARD_EVENT)
+        super().__init__(KEYBOARD_EVENT)
         self.id = event.id
         self.type = event.type
         self.hw_code = event.hw_code
         self.modifiers = event.modifiers
         self.event_string = event.event_string
+        self.keyval_name = ""
         self.is_text = event.is_text
-        self.time = time.time()
         self.timestamp = event.timestamp
-
-        # Add an empty field for the keyval_name because there are a number
-        # of places we might want to know this information, and we don't
-        # want to have to keep calculating it. The default calculation will
-        # take place in script.checkKeyboardEventData.
-        #
-        self.keyval_name = ""
-
-        # Call the specific toolkit method, to ensure that all fields
-        # are filled.
-        #
-        script = orca_state.activeScript
-        if script:
-            script.checkKeyboardEventData(self)
+        self.is_duplicate = self == orca_state.lastInputEvent
+        self._script = orca_state.activeScript
+        self._app = None
+        self._window = orca_state.activeWindow
+        self._obj = orca_state.locusOfFocus
+        self._handler = None
+        self._consumer = None
+        self._should_consume = None
+        self._consume_reason = None
+        self._did_consume = None
+        self._result_reason = None
+
+        if self._script:
+            self._script.checkKeyboardEventData(self)
+            self._app = self._script.app
+            if not self._window:
+                self._window = self._script.utilities.activeWindow()
 
         # Control characters come through as control characters, so we
         # just turn them into their ASCII equivalent.  NOTE that the
@@ -158,39 +126,52 @@ class KeyboardEvent(InputEvent):
             if value < 32:
                 self.event_string = chr(value + 0x40)
 
+        if self.is_duplicate:
+            KeyboardEvent.duplicateCount += 1
+        else:
+            KeyboardEvent.duplicateCount = 0
+
         self.keyType = None
+        _isPressed = event.type == pyatspi.KEY_PRESSED_EVENT
         if self.isNavigationKey():
             self.keyType = KeyboardEvent.TYPE_NAVIGATION
-            self.shouldEcho = settings.enableNavigationKeys
+            self.shouldEcho = _isPressed and settings.enableNavigationKeys
         elif self.isActionKey():
             self.keyType = KeyboardEvent.TYPE_ACTION
-            self.shouldEcho = settings.enableActionKeys
+            self.shouldEcho = _isPressed and settings.enableActionKeys
         elif self.isModifierKey():
             self.keyType = KeyboardEvent.TYPE_MODIFIER
-            self.shouldEcho = settings.enableModifierKeys
+            self.shouldEcho = _isPressed and settings.enableModifierKeys
+            if self.isOrcaModifier():
+                KeyboardEvent.orcaModifierPressed = _isPressed
         elif self.isFunctionKey():
             self.keyType = KeyboardEvent.TYPE_FUNCTION
-            self.shouldEcho = settings.enableFunctionKeys
+            self.shouldEcho = _isPressed and settings.enableFunctionKeys
         elif self.isDiacriticalKey():
             self.keyType = KeyboardEvent.TYPE_DIACRITICAL
-            self.shouldEcho = settings.enableDiacriticalKeys
+            self.shouldEcho = _isPressed and settings.enableDiacriticalKeys
         elif self.isLockingKey():
             self.keyType = KeyboardEvent.TYPE_LOCKING
             self.shouldEcho = settings.presentLockingKeys
             if self.shouldEcho == None:
                 self.shouldEcho = not settings.onlySpeakDisplayedText
+            self.shouldEcho = self.shouldEcho and _isPressed
         elif self.isAlphabeticKey():
             self.keyType = KeyboardEvent.TYPE_ALPHABETIC
-            self.shouldEcho = settings.enableAlphabeticKeys or settings.enableEchoByCharacter
+            self.shouldEcho = _isPressed \
+                and (settings.enableAlphabeticKeys or settings.enableEchoByCharacter)
         elif self.isNumericKey():
             self.keyType = KeyboardEvent.TYPE_NUMERIC
-            self.shouldEcho = settings.enableNumericKeys or settings.enableEchoByCharacter
+            self.shouldEcho = _isPressed \
+                and (settings.enableNumericKeys or settings.enableEchoByCharacter)
         elif self.isPunctuationKey():
             self.keyType = KeyboardEvent.TYPE_PUNCTUATION
-            self.shouldEcho = settings.enablePunctuationKeys or settings.enableEchoByCharacter
+            self.shouldEcho = _isPressed \
+                and (settings.enablePunctuationKeys or settings.enableEchoByCharacter)
         elif self.isSpace():
             self.keyType = KeyboardEvent.TYPE_SPACE
-            self.shouldEcho = settings.enableSpace or settings.enableEchoByCharacter
+            self.shouldEcho = _isPressed \
+                and (settings.enableSpace or settings.enableEchoByCharacter)
         else:
             self.keyType = KeyboardEvent.TYPE_UNKNOWN
             self.shouldEcho = False
@@ -198,29 +179,75 @@ class KeyboardEvent(InputEvent):
         if not self.isLockingKey():
             self.shouldEcho = self.shouldEcho and settings.enableKeyEcho
 
+        if not self.isModifierKey():
+            self.setClickCount()
+
+        if orca_state.bypassNextCommand and _isPressed:
+            KeyboardEvent.orcaModifierPressed = False
+
+        if KeyboardEvent.orcaModifierPressed:
+            self.modifiers |= keybindings.ORCA_MODIFIER_MASK
+
+        self._should_consume, self._consume_reason = self.shouldConsume()
+
+    def setClickCount(self):
+        """Updates the count of the number of clicks a user has made."""
+
+        lastEvent = orca_state.lastNonModifierKeyEvent
+        if not isinstance(lastEvent, KeyboardEvent) \
+           or lastEvent.event_string != self.event_string \
+           or self.time - lastEvent.time > settings.doubleClickTimeout:
+            self._clickCount = 1
+            return
+
+        self._clickCount = lastEvent.getClickCount()
+        if self.is_duplicate:
+            return
+
+        if self.type == pyatspi.KEY_RELEASED_EVENT:
+            return
+
+        if self._clickCount < 3:
+            self._clickCount += 1
+            return
+
+        self._clickCount = 1
+
     def __eq__(self, other):
         if not other:
             return False
 
-        if self.type == other.type \
-           and self.hw_code == other.hw_code \
-           and self.timestamp == other.timestamp:
-            return True
+        if self.type == other.type and self.hw_code == other.hw_code:
+            return self.timestamp == other.timestamp
 
         return False
 
-    def toString(self):
-        return ("KEYBOARDEVENT: type=%d\n" % self.type) \
-            + ("                id=%d\n" % self.id) \
-            + ("                hw_code=%d\n" % self.hw_code) \
-            + ("                modifiers=%d\n" % self.modifiers) \
-            + ("                event_string=(%s)\n" % self.event_string) \
-            + ("                keyval_name=(%s)\n" % self.keyval_name) \
-            + ("                is_text=%s\n" % self.is_text) \
-            + ("                timestamp=%d\n" % self.timestamp) \
-            + ("                time=%f\n" % time.time()) \
-            + ("                keyType=%s\n" % self.keyType) \
-            + ("                shouldEcho=%s\n" % self.shouldEcho)
+    def __str__(self):
+        return ("KEYBOARD_EVENT:  type=%d\n" % self.type) \
+             + ("                 id=%d\n" % self.id) \
+             + ("                 hw_code=%d\n" % self.hw_code) \
+             + ("                 modifiers=%d\n" % self.modifiers) \
+             + ("                 event_string=(%s)\n" % self.event_string) \
+             + ("                 keyval_name=(%s)\n" % self.keyval_name) \
+             + ("                 is_text=%s\n" % self.is_text) \
+             + ("                 timestamp=%d\n" % self.timestamp) \
+             + ("                 time=%f\n" % time.time()) \
+             + ("                 keyType=%s\n" % self.keyType) \
+             + ("                 clickCount=%s\n" % self._clickCount) \
+             + ("                 shouldEcho=%s\n" % self.shouldEcho)
+
+    def _isReleaseForLastNonModifierKeyEvent(self):
+        last = orca_state.lastNonModifierKeyEvent
+        if not last:
+            return False
+
+        if not last.isPressedKey() or self.isPressedKey():
+            return False
+
+        if self.id == last.id and self.hw_code == last.hw_code:
+            return self.modifiers == last.modifiers
+
+        return False
 
     def isNavigationKey(self):
         """Return True if this is a navigation key."""
@@ -310,10 +337,10 @@ class KeyboardEvent(InputEvent):
 
         return self.event_string.isnumeric()
 
-    def isOrcaModifier(self):
+    def isOrcaModifier(self, checkBypassMode=True):
         """Return True if this is the Orca modifier key."""
 
-        if orca_state.bypassNextCommand:
+        if checkBypassMode and orca_state.bypassNextCommand:
             return False
 
         if self.event_string in settings.orcaModifierKeys:
@@ -421,6 +448,157 @@ class KeyboardEvent(InputEvent):
 
         return keynames.getKeyName(self.event_string)
 
+    def shouldConsume(self):
+        """Returns True if this event should be consumed."""
+
+        if not self.timestamp:
+            return False, 'No timestamp'
+
+        if not self._script:
+            return False, 'No active script when received'
+
+        if orca_state.capturingKeys:
+            return False, 'Capturing keys'
+
+        self._handler = self._script.keyBindings.getInputHandler(self)
+        if self._handler:
+            scriptConsumes = self._script.consumesKeyboardEvent(self)
+        else:
+            scriptConsumes = False
+
+        if self.is_duplicate:
+            return scriptConsumes, 'Consuming based on handler'
+
+        if self._isReleaseForLastNonModifierKeyEvent():
+            return scriptConsumes, 'Is release for last non-modifier keyevent'
+
+        if orca_state.learnModeEnabled:
+            if self.event_string == 'Escape':
+                self._consumer = self._script.exitLearnMode
+                return True, 'Exiting Learn Mode'
+
+            if self.event_string == 'F1' and not self.modifiers:
+                self._consumer = self._script.showHelp
+                return True, 'Showing Help'
+
+            if self.event_string in ['F2', 'F3'] and not self.modifiers:
+                self._consumer = self._script.listOrcaShortcuts
+                return True, 'Listing shortcuts'
+
+            self._consumer = self._presentHandler
+            return True, 'In Learn Mode'
+
+        if self.isModifierKey():
+            if not self.isOrcaModifier():
+                return False, 'Non-Orca modifier not in Learn Mode'
+            return True, 'Orca modifier'
+
+        if orca_state.listNotificationsModeEnabled:
+            return True, 'Listing notifications'
+
+        if not self._handler:
+            return False, 'No handler'
+
+        return scriptConsumes, 'Script indication'
+
+    def didConsume(self):
+        """Returns True if this event was consumed."""
+
+        if self._did_consume is not None:
+            return self._did_consume
+
+        return False
+
+    def _present(self, inputEvent=None):
+        if self.isPressedKey():
+            self._script.presentationInterrupt()
+
+        return self._script.presentKeyboardEvent(self)
+
+    def _presentHandler(self, input_event=None):
+        if not self._handler:
+            return False
+
+        if self._handler.learnModeEnabled and self._handler.description:
+            self._script.presentMessage(self._handler.description)
+
+        return True
+
+    def process(self):
+        """Processes this input event."""
+
+        startTime = time.time()
+        data = "'%s' (%d)" % (self.event_string, self.hw_code)
+        if self.is_duplicate:
+            data = '%s DUPLICATE EVENT #%i' % (data, KeyboardEvent.duplicateCount)
+
+        msg = '\nvvvvv PROCESS %s: %s vvvvv' % (self.type.value_name.upper(), data)
+        debug.println(debug.LEVEL_INFO, msg, False)
+
+        self._did_consume, self._result_reason = self._process()
+
+        msg = 'HOST_APP: %s' % self._app
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        msg = 'WINDOW:   %s' % self._window
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        msg = 'LOCATION: %s' % self._obj
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        msg = 'CONSUME:  %s (%s)' % (self._should_consume, self._consume_reason)
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        if self._should_consume != self._did_consume:
+            msg = 'CONSUMED: %s (%s)' % (self._did_consume, self._result_reason)
+            debug.println(debug.LEVEL_INFO, msg, True)
+
+        msg = 'TOTAL PROCESSING TIME: %.4f' % (time.time() - startTime)
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        msg = '^^^^^ PROCESS %s: %s ^^^^^\n' % (self.type.value_name.upper(), data)
+        debug.println(debug.LEVEL_INFO, msg, False)
+
+        return self._did_consume
+
+    def _process(self):
+        """Processes this input event."""
+
+        orca_state.lastInputEvent = self
+        if not self.isModifierKey():
+            orca_state.lastNonModifierKeyEvent = self
+
+        if not self._script:
+            return False, 'No active script'
+
+        if self.is_duplicate or not self.isPressedKey():
+            return self._should_consume, 'Consumed based on handler'
+
+        self._present()
+
+        if self.isOrcaModifier():
+            return True, 'Orca modifier'
+
+        if orca_state.bypassNextCommand:
+            orca_state.bypassNextCommand = False
+            return False, 'Bypass next command'
+
+        if not self._should_consume:
+            return False, 'Should not consume'
+
+        if not (self._consumer or self._handler):
+            return False, 'No consumer or handler'
+
+        if self._consumer:
+            self._consumer(self)
+            return True, 'Consumed by consumer'
+
+        if self._should_consume and self._handler.function:
+            self._handler.function(self._script, self)
+            return True, 'Consumed by handler'
+
+        return False, 'Unaddressed case'
+
 class BrailleEvent(InputEvent):
 
     def __init__(self, event):
@@ -429,20 +607,38 @@ class BrailleEvent(InputEvent):
         Arguments:
         - event: the integer BrlTTY command for this event.
         """
-        InputEvent.__init__(self, BRAILLE_EVENT)
+        super().__init__(BRAILLE_EVENT)
         self.event = event
 
 class MouseButtonEvent(InputEvent):
 
     def __init__(self, event):
-        """Creates a new InputEvent of type MOUSE_BUTTON_EVENT.
-        """
-        InputEvent.__init__(self, MOUSE_BUTTON_EVENT)
+        """Creates a new InputEvent of type MOUSE_BUTTON_EVENT."""
+
+        super().__init__(MOUSE_BUTTON_EVENT)
         self.x = event.detail1
         self.y = event.detail2
         self.pressed = event.type.endswith('p')
         self.button = event.type[len("mouse:button:"):-1]
-        self.time = time.time()
+
+    def setClickCount(self):
+        """Updates the count of the number of clicks a user has made."""
+
+        if not self.pressed:
+            return
+
+        if not isinstance(lastInputEvent, MouseButtonEvent):
+            self._clickCount = 1
+            return
+
+        if self.time - lastInputEvent.time < settings.doubleClickTimeout \
+            and lastInputEvent.button == self.button:
+            if self._clickCount < 2:
+                self._clickCount += 1
+                return
+
+        self._clickCount = 1
+
 
 class InputEventHandler:
 
@@ -465,7 +661,7 @@ class InputEventHandler:
 
         self.function = function
         self.description = description
-        self._learnModeEnabled = learnModeEnabled
+        self.learnModeEnabled = learnModeEnabled
 
     def __eq__(self, other):
         """Compares one input handler to another."""
diff --git a/src/orca/keybindings.py b/src/orca/keybindings.py
index cd88c24..5bb5dfb 100644
--- a/src/orca/keybindings.py
+++ b/src/orca/keybindings.py
@@ -417,24 +417,6 @@ class KeyBindings:
 
         return None
 
-    def consumeKeyboardEvent(self, script, keyboardEvent):
-        """Attempts to consume the given keyboard event.  If these
-        keybindings have a handler for the given keyboardEvent, it is
-        assumed the event will always be consumed.
-        """
-
-        consumed = False
-        handler = self.getInputHandler(keyboardEvent)
-        if handler:
-            consumed = True
-            if keyboardEvent.type == pyatspi.KEY_PRESSED_EVENT:
-                try:
-                    handler.processInputEvent(script, keyboardEvent)
-                except:
-                    debug.printException(debug.LEVEL_SEVERE)
-
-        return consumed
-
     def load(self, keymap, handlers):
         """ Takes the keymappings and tries to find a matching named
            function in handlers.
diff --git a/src/orca/notification_messages.py b/src/orca/notification_messages.py
index c72e1ca..7303a23 100644
--- a/src/orca/notification_messages.py
+++ b/src/orca/notification_messages.py
@@ -31,6 +31,7 @@ from . import cmdnames
 from . import debug
 from . import input_event
 from . import messages
+from . import orca_state
 
 # to store  the messages generated by the notification daemon
 notificationMessages = []
@@ -41,9 +42,6 @@ maxSizeList = 55
 # a index to walk in the list of messages
 indexNotificationMessages = 0
 
-# when True the list mode is enabled
-listNotificationMessagesModeEnabled = False
-
 # number of keys invalid while in when in list notification mode.
 # if > 3, call _help()
 invalidKeys = 0
@@ -116,12 +114,11 @@ def _listModeEnable(script):
     """ enable the list mode if the queue is not empty """
 
     global indexNotificationMessages
-    global listNotificationMessagesModeEnabled
     global invalidKeys
     if _messagesPresent(script):
         indexNotificationMessages = 1
         invalidKeys = 0
-        listNotificationMessagesModeEnabled = True
+        orca_state.listNotificationsModeEnabled = True
         _help(script, True)
         _showNotificationMessage(script, indexNotificationMessages)
 
@@ -151,8 +148,7 @@ def _showNotificationMessage(script, index):
 def exitListNotificationMessagesMode(script):
     """ Turns list notification messages mode off. """
 
-    global listNotificationMessagesModeEnabled
-    listNotificationMessagesModeEnabled = False
+    orca_state.listNotificationsModeEnabled = False
     _showMessage(script, messages.NOTIFICATION_LIST_EXIT)
 
 def listNotificationMessages(script, event):
diff --git a/src/orca/orca.py b/src/orca/orca.py
index aee13a1..7e3c76c 100644
--- a/src/orca/orca.py
+++ b/src/orca/orca.py
@@ -78,7 +78,6 @@ from . import settings_manager
 from . import speech
 from . import sound
 from .input_event import BrailleEvent
-from .input_event import KeyboardEvent
 
 _eventManager = event_manager.getManager()
 _scriptManager = script_manager.getManager()
@@ -188,103 +187,6 @@ def setLocusOfFocus(event, obj, notifyScript=True, force=False):
 
 ########################################################################
 #                                                                      #
-# METHODS FOR PRE-PROCESSING AND MASSAGING KEYBOARD EVENTS.            #
-#                                                                      #
-########################################################################
-
-_orcaModifierPressed = False
-
-def _processKeyboardEvent(event):
-    """The primary key event handler for Orca.  Keeps track of various
-    attributes, such as the lastInputEvent.  Also does key echo as well
-    as any local keybindings before passing the event on to the active
-    script.  This method is called synchronously from the AT-SPI registry
-    and should be performant.  In addition, it must return True if it has
-    consumed the event (and False if not).
-
-    Arguments:
-    - event: an AT-SPI DeviceEvent
-
-    Returns True if the event should be consumed.
-    """
-    global _orcaModifierPressed
-
-    keyboardEvent = KeyboardEvent(event)
-    debug.println(debug.LEVEL_FINE, keyboardEvent.toString())
-
-    # Weed out duplicate and otherwise bogus events.
-    # TODO - JD: Be sure these are the right values to return
-    if not keyboardEvent.timestamp:
-        debug.println(debug.LEVEL_FINE, "IGNORING EVENT: NO TIMESTAMP")
-        return False
-    if keyboardEvent == orca_state.lastInputEvent:
-        debug.println(debug.LEVEL_FINE, "IGNORING EVENT: DUPLICATE")
-        return False
-
-    # Figure out what we've got.
-    isOrcaModifier = keyboardEvent.isOrcaModifier()
-    isPressedEvent = keyboardEvent.isPressedKey()
-    if isOrcaModifier:
-        _orcaModifierPressed = isPressedEvent
-    if _orcaModifierPressed:
-        keyboardEvent.modifiers |= keybindings.ORCA_MODIFIER_MASK
-
-    # Update our state.
-    orca_state.lastInputEvent = keyboardEvent
-    if not keyboardEvent.isModifierKey():
-        keyboardEvent.setClickCount()
-        orca_state.lastNonModifierKeyEvent = keyboardEvent
-
-    # Echo it based on what it is and the user's settings.
-    script = orca_state.activeScript
-    if not script:
-        debug.println(debug.LEVEL_FINE, "IGNORING EVENT DUE TO NO SCRIPT")
-        return False
-
-    if isPressedEvent:
-        if not orca_state.activeWindow:
-            orca_state.activeWindow = script.utilities.activeWindow()
-        script.presentationInterrupt()
-    script.presentKeyboardEvent(keyboardEvent)
-    if keyboardEvent.isModifierKey() and not isOrcaModifier:
-        return orca_state.learnModeEnabled
- 
-    # Special modes.
-    if not isPressedEvent and keyboardEvent.event_string == "Escape":
-        script.exitLearnMode(keyboardEvent)
-    if orca_state.learnModeEnabled and not keyboardEvent.modifiers:
-        if keyboardEvent.event_string == "F1":
-            orca_state.learnModeEnabled = False
-            return helpForOrca()
-        if isPressedEvent and keyboardEvent.event_string in ["F2", "F3"]:
-            return script.listOrcaShortcuts(keyboardEvent)
-    if orca_state.capturingKeys:
-        return False
-    if notification_messages.listNotificationMessagesModeEnabled:
-        return notification_messages.listNotificationMessages(script, keyboardEvent)
-
-    # See if the event manager wants it (i.e. it is bound to a command.
-    if _eventManager.processKeyboardEvent(keyboardEvent):
-        return True
-
-    # Do any needed xmodmap crap.
-    global _restoreOrcaKeys
-    if not isPressedEvent:
-        if keyboardEvent.event_string in settings.orcaModifierKeys \
-           and orca_state.bypassNextCommand:
-            _restoreXmodmap()
-            _restoreOrcaKeys = True
-        elif _restoreOrcaKeys and not orca_state.bypassNextCommand:
-            _createOrcaXmodmap()
-            _restoreOrcaKeys = False
-    elif not keyboardEvent.isModifierKey():
-        _orcaModifierPressed = False
-        orca_state.bypassNextCommand = False
- 
-    return isOrcaModifier or orca_state.learnModeEnabled
-
-########################################################################
-#                                                                      #
 # METHODS FOR PRE-PROCESSING AND MASSAGING BRAILLE EVENTS.             #
 #                                                                      #
 ########################################################################
@@ -323,6 +225,23 @@ def _processBrailleEvent(event):
 #                                                                      #
 ########################################################################
 
+def updateKeyMap(keyboardEvent):
+    """Unsupported convenience method to call sad hacks which should go away."""
+
+    global _restoreOrcaKeys
+    if keyboardEvent.isPressedKey():
+        return
+
+    if keyboardEvent.event_string in settings.orcaModifierKeys \
+       and orca_state.bypassNextCommand:
+        _restoreXmodmap()
+        _restoreOrcaKeys = True
+        return
+
+    if _restoreOrcaKeys and not orca_state.bypassNextCommand:
+        _createOrcaXmodmap()
+        _restoreOrcaKeys = False
+
 def _setXmodmap(xkbmap):
     """Set the keyboard map using xkbcomp."""
     p = subprocess.Popen(['xkbcomp', '-w0', '-', os.environ['DISPLAY']],
@@ -547,6 +466,7 @@ def helpForOrca(script=None, inputEvent=None, page=""):
 
     Returns True to indicate the input event has been consumed.
     """
+    orca_state.learnModeEnabled = False
     uri = "help:orca"
     if page:
         uri += "?%s" % page
@@ -605,7 +525,6 @@ def init(registry):
         signal.alarm(settings.timeoutTime)
 
     loadUserSettings()
-    _eventManager.registerKeystrokeListener(_processKeyboardEvent)
 
     if settings.timeoutCallback and (settings.timeoutTime > 0):
         signal.alarm(0)
@@ -696,8 +615,6 @@ def shutdown(script=None, inputEvent=None):
     orca_state.activeScript.presentMessage(messages.STOP_ORCA)
 
     _scriptManager.deactivate()
-
-    _eventManager.deregisterKeystrokeListener(_processKeyboardEvent)
     _eventManager.deactivate()
 
     # Shutdown all the other support.
diff --git a/src/orca/orca_state.py b/src/orca/orca_state.py
index 30dcb58..bb8bd49 100644
--- a/src/orca/orca_state.py
+++ b/src/orca/orca_state.py
@@ -74,3 +74,5 @@ learnModeEnabled = False
 # Handle to the Orca Preferences Glade GUI object.
 #
 orcaOS = None
+
+listNotificationsModeEnabled = False
diff --git a/src/orca/script.py b/src/orca/script.py
index f31ceff..a717023 100644
--- a/src/orca/script.py
+++ b/src/orca/script.py
@@ -481,52 +481,6 @@ class Script:
                 consumes = handler != None
         return consumes
 
-    def processKeyboardEvent(self, keyboardEvent):
-        """Processes the given keyboard event.
-
-        This method will primarily use the keybindings field of this
-        script instance see if this script has an interest in the
-        event.
-
-        NOTE: there is latent, but unsupported, logic for allowing
-        the user's user-settings.py file to extend and/or override
-        the keybindings for a script.
-
-        Arguments:
-        - keyboardEvent: an instance of input_event.KeyboardEvent
-        """
-
-        # We'll annotate the event with a reference to this script.
-        # This will allow external scripts to muck with the script
-        # instance if they wish.
-        #
-        keyboardEvent.script = self
-
-        # We'll let the user keybindings take precedence.  First, we'll
-        # check to see if they have keybindings specific for the particular
-        # application, then we'll check to see if they have any default
-        # bindings to use.
-        #
-        # [[[TODO: WDW - for performance, these bindings should probably
-        # be conflated at initialization time.]]]
-        #
-        user_bindings = None
-
-        user_bindings_map = settings.keyBindingsMap
-        if self.__module__ in user_bindings_map:
-            user_bindings = user_bindings_map[self.__module__]
-        elif "default" in user_bindings_map:
-            user_bindings = user_bindings_map["default"]
-
-        consumed = False
-        if user_bindings:
-            consumed = user_bindings.consumeKeyboardEvent(self,
-                                                          keyboardEvent)
-        if not consumed:
-            consumed = self.keyBindings.consumeKeyboardEvent(self,
-                                                             keyboardEvent)
-        return consumed
-
     def consumesBrailleEvent(self, brailleEvent):
         """Called when a key is pressed on the braille display.
 
diff --git a/src/orca/scripts/default.py b/src/orca/scripts/default.py
index e551bc2..02b4b20 100644
--- a/src/orca/scripts/default.py
+++ b/src/orca/scripts/default.py
@@ -926,9 +926,21 @@ class Script(script.Script):
         orca_state.learnModeEnabled = False
         return True
 
+    def showHelp(self, inputEvent=None):
+        return orca.helpForOrca()
+
+    def listNotifications(self, inputEvent=None):
+        if inputEvent is None:
+            inputEvent = orca_state.lastNonModifierKeyEvent
+
+        return notification_messages.listNotificationMessages(self, inputEvent)
+
     def listOrcaShortcuts(self, inputEvent=None):
         """Shows a simple gui listing Orca's bound commands."""
 
+        if inputEvent is None:
+            inputEvent = orca_state.lastNonModifierKeyEvent
+
         if not inputEvent or inputEvent.event_string == "F2":
             bound = self.getDefaultKeyBindings().getBoundBindings()
             title = messages.shortcutsFoundOrca(len(bound))
@@ -2790,7 +2802,7 @@ class Script(script.Script):
             orca_state.activeWindow = None
 
         # disable list notification  messages mode
-        notification_messages.listNotificationMessagesModeEnabled = False
+        orca_state.listNotificationsModeEnabled = False
 
         # disable learn mode
         orca_state.learnModeEnabled = False
diff --git a/src/orca/scripts/self_voicing.py b/src/orca/scripts/self_voicing.py
index b75fc5c..a29e42d 100644
--- a/src/orca/scripts/self_voicing.py
+++ b/src/orca/scripts/self_voicing.py
@@ -59,16 +59,6 @@ class Script(default.Script):
         """
         pass
 
-    def processKeyboardEvent(self, keyboardEvent):
-        """Does nothing.
-
-        Arguments:
-        - keyboardEvent: an instance of input_event.KeyboardEvent
-
-        Returns False to indicate the event was not consumed.
-        """
-        return False
-
     def processBrailleEvent(self, brailleEvent):
         """Does nothing.
 


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