orca r4219 - branches/phase2/src/orca



Author: wwalker
Date: Mon Sep 15 01:09:42 2008
New Revision: 4219
URL: http://svn.gnome.org/viewvc/orca?rev=4219&view=rev

Log:
Add click count and also get braille working again.


Modified:
   branches/phase2/src/orca/braille.py
   branches/phase2/src/orca/input_bindings.py
   branches/phase2/src/orca/input_event.py
   branches/phase2/src/orca/orca.py
   branches/phase2/src/orca/plugin.py
   branches/phase2/src/orca/script.py
   branches/phase2/src/orca/script_manager.py

Modified: branches/phase2/src/orca/braille.py
==============================================================================
--- branches/phase2/src/orca/braille.py	(original)
+++ branches/phase2/src/orca/braille.py	Mon Sep 15 01:09:42 2008
@@ -212,6 +212,7 @@
         for key in keys:
             keySet.append(brlapi.KEY_TYPE_CMD | key)
         _brlAPI.acceptKeys(brlapi.rangeType_command, keySet)
+        log.debug("set braille key ranges to %s", keySet)
     except:
         log.exception("handled exception while setting up braille key ranges:")
 

Modified: branches/phase2/src/orca/input_bindings.py
==============================================================================
--- branches/phase2/src/orca/input_bindings.py	(original)
+++ branches/phase2/src/orca/input_bindings.py	Mon Sep 15 01:09:42 2008
@@ -369,7 +369,7 @@
         """
         handler = self.getHandler(commandCode,
                                   modifiers,
-                                  script.getClickCount())
+                                  inputEvent.click_count)
         if handler and process:
             handler.processInputEvent(script,
                                       inputEvent,

Modified: branches/phase2/src/orca/input_event.py
==============================================================================
--- branches/phase2/src/orca/input_event.py	(original)
+++ branches/phase2/src/orca/input_event.py	Mon Sep 15 01:09:42 2008
@@ -172,14 +172,15 @@
         self.event_string = event_string
         self.is_text = event.is_text
         self.time = time.time()
+        self.click_count = 0
 
     def __str__(self):
         if self.type == pyatspi.KEY_PRESSED_EVENT:
-            s = "key '%s' pressed (mods=0x%x)" \
-                % (self.event_string, self.modifiers)
+            s = "key '%s' pressed (modifiers=0x%x, click_count=%d)" \
+                % (self.event_string, self.modifiers, self.click_count)
         else:
-            s = "key '%s' released (mods=0x%x)" \
-                % (self.event_string, self.modifiers)
+            s = "key '%s' released (modifiers=0x%x, click_count=%d)" \
+                % (self.event_string, self.modifiers, self.click_count)
         return s
 
 class BrailleEvent(InputEvent):
@@ -196,9 +197,12 @@
         self.type = event["type"]
         self.argument = event["argument"]
         self.flags = event["flags"]
+        self.time = time.time()
+        self.click_count = 0
 
     def __str__(self):
-        return "braille event %s" % self.event
+        return "braille event %s (click_count=%d)" \
+               % (self.event, self.click_count)
 
 class MouseButtonEvent(InputEvent):
     """An InputEvent that comes from pressing a mouse button."""
@@ -211,14 +215,15 @@
         self.pressed = event.type.endswith('p')
         self.button = event.type[len("mouse:button:"):-1]
         self.time = time.time()
+        self.click_count = 0
 
     def __str__(self):
         if self.pressed:
-            s = "mouse button '%s' pressed at (%d,%y)" \
-                % (self.button, self.x, self.y)
+            s = "mouse button '%s' pressed at (%d,%y) (click_count=%d)" \
+                % (self.button, self.x, self.y, self.click_count)
         else:
-            s = "mouse button '%s' released at (%d,%y)" \
-                % (self.button, self.x, self.y)
+            s = "mouse button '%s' released at (%d,%y) (click_count=%d)" \
+                % (self.button, self.x, self.y, self.click_count)
         return s
 
 if __name__ == "__main__":

Modified: branches/phase2/src/orca/orca.py
==============================================================================
--- branches/phase2/src/orca/orca.py	(original)
+++ branches/phase2/src/orca/orca.py	Mon Sep 15 01:09:42 2008
@@ -18,7 +18,6 @@
 # TODO: key echo (perhaps move this to the script itself?)
 # TODO: speech stopping on mouse buttons (perhaps in script itself?)
 # TODO: learn mode (maybe in script manager?)
-# TODO: click count (maybe in script manager?)
 # TODO: recording of keystrokes for setting key bindings (maybe in script?)
 # TODO: toggling of speech on/off (maybe per script?)
 # TODO: loading of user settings

Modified: branches/phase2/src/orca/plugin.py
==============================================================================
--- branches/phase2/src/orca/plugin.py	(original)
+++ branches/phase2/src/orca/plugin.py	Mon Sep 15 01:09:42 2008
@@ -52,6 +52,22 @@
         """
         return "plugin %s for %s" % (self.__module__, self._script)
 
+    def _setupBrailleKeyRanges(self):
+        """Sets up the BrlAPI commands this script and all of its plugins
+        care about.
+        """
+        # We let the script do this -- the BrlTTY API is such that the
+        # setting is done in one fell swoop.
+        pass
+
+    def _clearBrailleKeyRanges(self):
+        """Clears the BrlAPI commands this script and all of its plugins
+        care about.
+        """
+        # We let the script do this -- the BrlTTY API is such that the
+        # setting is done in one fell swoop.
+        pass
+
     def getPronunciations(self):
         """Defines the application specific pronunciations for this script.
 
@@ -60,11 +76,6 @@
         """
         return self._script.getPronunciations()
 
-    def getClickCount(self):
-        """Returns the click count of the last input event."""
-        return self._script.getClickCount()
-
-
 if __name__ == "__main__":
     logging.basicConfig(format="%(name)s %(message)s")
     log.setLevel(logging.DEBUG)

Modified: branches/phase2/src/orca/script.py
==============================================================================
--- branches/phase2/src/orca/script.py	(original)
+++ branches/phase2/src/orca/script.py	Mon Sep 15 01:09:42 2008
@@ -159,20 +159,29 @@
         """
         return {}
 
-    def getClickCount(self):
-        """Returns the click count of the last input event."""
-        # TODO: implement click count
-        return 1
-
-    def getBrailleKeys(self):
-        """Returns the BrlAPI commands this script and all of its plugins
+    def _getBrailleKeyRanges(self):
+        """Gets the BrlAPI commands this script and all of its plugins
         care about.
         """
         keys = []
         for binding in self._brailleBindings:
             keys.append(binding.command)
+        for plugin in self._plugins:
+            keys += plugin._getBrailleKeyRanges()
         return keys
 
+    def _setupBrailleKeyRanges(self):
+        """Sets up the BrlAPI commands this script and all of its plugins
+        care about.
+        """
+        braille.setupKeyRanges(self._getBrailleKeyRanges())
+
+    def _clearBrailleKeyRanges(self):
+        """Clears the BrlAPI commands this script and all of its plugins
+        care about.
+        """
+        braille.setupKeyRanges([])
+
     def getInputEventHandlerKey(self, inputEventHandler):
         """Returns the name of the key that contains an inputEventHadler
         passed as argument
@@ -199,7 +208,7 @@
             handler = self._keyBindings.getHandler(
                 keyboardEvent.hw_code,
                 keyboardEvent.modifiers,
-                self.getClickCount())
+                keyboardEvent.click_count)
             consumes = handler != None
         if not consumes:
             for plugin in self._plugins:
@@ -242,7 +251,7 @@
             handler = self._brailleBindings.getHandler(
                 brailleEvent.command,
                 0, # TODO: add current keyboard modifiers
-                self.getClickCount())
+                brailleEvent.click_count)
             consumes = handler != None
         if not consumes:
             for plugin in self._plugins:
@@ -259,7 +268,6 @@
         - brailleEvent: an instance of input_event.BrailleEvent
         """
         # TODO: add support for user-settings.py brailleBindingsMap
-        log.debug("processBrailleEvent %s" % brailleEvent)
 
         # We'll annotate the event with a reference to this script.
         # This will allow external scripts to muck with the script
@@ -271,7 +279,7 @@
             brailleEvent,
             0) # TODO: add current keyboard modifiers
         for plugin in self._plugins:
-            plugin.processKeyboardEvent(brailleEvent)
+            plugin.processBrailleEvent(brailleEvent)
 
     def processObjectEvent(self, event):
         """Processes all AT-SPI object events of interest to this
@@ -317,11 +325,8 @@
 
         for eventType in self._objectEventListeners.keys():
             utils.registerEventListener(eventType)
-
-        keys = []
-        for scrypt in [self] + self._plugins:
-            keys += scrypt.getBrailleKeys()
-        braille.setupKeyRanges(keys)
+        
+        self._setupBrailleKeyRanges()
 
         for plugin in self._plugins:
             plugin.activate()
@@ -344,7 +349,7 @@
         for eventType in self._objectEventListeners.keys():
             utils.deregisterEventListener(eventType)
 
-        braille.setupKeyRanges([])
+        self._clearBrailleKeyRanges()
 
         self._isActive = False
 

Modified: branches/phase2/src/orca/script_manager.py
==============================================================================
--- branches/phase2/src/orca/script_manager.py	(original)
+++ branches/phase2/src/orca/script_manager.py	Mon Sep 15 01:09:42 2008
@@ -38,6 +38,13 @@
 LAPTOP_MODIFIER_KEYS  = ["Caps_Lock"]
 orcaModifierKeys      = DESKTOP_MODIFIER_KEYS
 
+# Keyboard double-click period. If the same key is pressed within
+# this time period, it's considered to be a double-click and might
+# provide different functionality (for example, Numpad 5 double-click
+# spells the current word rather than speaks it).
+#
+doubleClickTimeout = 0.5
+
 # A list of toolkits whose events we need to process synchronously.
 # The only one right now is the Java toolkit (see bug #531869), but
 # we put this here to allow more toolkits to be more easily added
@@ -127,6 +134,8 @@
             self._processKeyboardEvent,
             mask=masks,
             kind=(pyatspi.KEY_PRESSED_EVENT, pyatspi.KEY_RELEASED_EVENT))
+        self._clickCount = 0
+        self._lastNonModifierEvent = None
 
         braille.init(self._processBrailleEvent)
 
@@ -371,6 +380,60 @@
         """
         log.debug(event)
 
+    def _isModifierKey(self, event_string):
+        """Return an indication of whether this is a modifier key.
+
+        Arguments:
+        - event: the event string
+
+        Returns True if this is a modifier key
+        """
+        modifierKeys = orcaModifierKeys \
+            + [ 'Alt_L', 'Alt_R', 'Control_L', 'Control_R',
+                'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R' ]
+        return event_string in modifierKeys
+
+    def _setClickCount(self, inputEvent):
+        """Sets the count of the number of clicks a user has made to
+        one of the non-modifier keys on the keyboard, braille display,
+        or mouse.  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.
+        """
+        lastInputEvent = self._lastNonModifierEvent
+
+        if (isinstance(inputEvent, input_event.KeyboardEvent) \
+                and (inputEvent.type == pyatspi.KEY_RELEASED_EVENT)) \
+            or (isinstance(inputEvent, input_event.MouseButtonEvent) \
+                and not inputEvent.pressed):
+            return
+
+        if not lastInputEvent \
+            or not isinstance(inputEvent, lastInputEvent.__class__):
+            self._clickCount = 1
+        elif isinstance(lastInputEvent, input_event.KeyboardEvent) \
+            and ((lastInputEvent.event_string != inputEvent.event_string) \
+                 or (lastInputEvent.modifiers != inputEvent.modifiers)):
+            self._clickCount = 1
+        elif isinstance(lastInputEvent, input_event.MouseButtonEvent) \
+            and (lastInputEvent.button != inputEvent.button):
+            self._clickCount = 1
+        elif isinstance(lastInputEvent, input_event.BrailleEvent) \
+            and (lastInputEvent.command != inputEvent.command):
+            self._clickCount = 1
+        elif (inputEvent.time - lastInputEvent.time) < doubleClickTimeout:
+            self._clickCount = min(3, self._clickCount + 1)
+        else:
+            self._clickCount = 1
+        
+        inputEvent.click_count = self._clickCount
+
+        log.debug("set _clickCount to %d for %s" 
+                  % (self._clickCount, inputEvent))
+
     def _processKeyboardEvent(self, event):
         """Processes the given keyboard event based on the keybinding from the
         currently active script. This method is called synchronously from the
@@ -384,6 +447,18 @@
         """
         keyboardEvent = input_event.KeyboardEvent(event)
 
+        # If this is a key event for a non-modifier key, save a handle
+        # to it.  This is needed to help determine user actions when a
+        # multi-key chord has been pressed, and we might get the key
+        # events in different orders.  See comment #15 of bug #435201
+        # for more details.  We also want to store the "click count"
+        # for the purpose of supporting keybindings with unique
+        # behaviors when double- or triple-clicked.
+        #
+        if not self._isModifierKey(keyboardEvent.event_string):
+            self._setClickCount(keyboardEvent)
+            self._lastNonModifierEvent = keyboardEvent
+
         isOrcaModifier = orcaModifierKeys.count(keyboardEvent.event_string) > 0
         if keyboardEvent.type == pyatspi.KEY_PRESSED_EVENT:
             if isOrcaModifier:
@@ -413,6 +488,8 @@
         Returns True if the command was consumed; otherwise False
         """
         brailleEvent = input_event.BrailleEvent(event)
+        self._lastNonModifierEvent = brailleEvent
+        self._setClickCount(brailleEvent)
         consume = self._activeScript \
                   and self._activeScript.consumesBrailleEvent(brailleEvent)
         if consume:



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