[orca] Add new methods needed for the keyboard-and-event refactor in progress.
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Add new methods needed for the keyboard-and-event refactor in progress.
- Date: Mon, 26 Dec 2011 20:45:16 +0000 (UTC)
commit 6f3f557acb446ea233fb25bc5d88cc47cb63aa02
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Mon Dec 26 15:44:16 2011 -0500
Add new methods needed for the keyboard-and-event refactor in progress.
src/orca/braille.py | 10 +++
src/orca/input_event.py | 153 ++++++++++++++++++++++++++++++++++++++-----
src/orca/keybindings.py | 66 +++++++++++++++++--
src/orca/scripts/default.py | 25 +++++++
4 files changed, 230 insertions(+), 24 deletions(-)
---
diff --git a/src/orca/braille.py b/src/orca/braille.py
index 203b75d..d30bcaf 100644
--- a/src/orca/braille.py
+++ b/src/orca/braille.py
@@ -1569,6 +1569,16 @@ def displayMessage(message, cursor=-1, flashTime=0):
setFocus(region)
refresh(True, stopFlash=False)
+def displayKeyEvent(event):
+ """Displays a KeyboardEvent. Typically reserved for locking keys like
+ Caps Lock and Num Lock."""
+
+ lockingStateString = event.getLockingStateString()
+ if lockingStateString:
+ keyname = event.getKeyName()
+ msg = "%s %s" % (keyname, lockingStateString)
+ displayMessage(msg, flashTime=settings.brailleFlashTime)
+
def panLeft(panAmount=0):
"""Pans the display to the left, limiting the pan to the beginning
of the line being displayed.
diff --git a/src/orca/input_event.py b/src/orca/input_event.py
index 9a1d034..9dbc5e1 100644
--- a/src/orca/input_event.py
+++ b/src/orca/input_event.py
@@ -18,17 +18,13 @@
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
-"""Provides support for handling input events. This provides several classes
-to define input events (InputEvent, KeyboardEvent, BrailleEvent,
-MouseButtonEvent, MouseMotionEvent, and SpeechEvent), and also provides a
-InputEventHandler class. It is intended that instances of InputEventHandler
-will be used which should be used to handle all input events."""
+"""Provides support for handling input events."""
__id__ = "$Id$"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc." \
- "Copyright (c) 2010-2011 Igalia, S.L."
+ "Copyright (c) 2011 Igalia, S.L."
__license__ = "LGPL"
import pyatspi
@@ -36,8 +32,10 @@ import time
import unicodedata
import debug
+import keynames
import orca_state
import settings
+from orca_i18n import C_
KEYBOARD_EVENT = "keyboard"
BRAILLE_EVENT = "braille"
@@ -51,12 +49,53 @@ class InputEvent:
"""Creates a new input event of the given type.
Arguments:
- - eventType: the input event type (one of KEYBOARD_EVENT, BRAILLE_EVENT,
- MOUSE_BUTTON_EVENT, MOUSE_MOTION_EVENT, SPEECH_EVENT).
+ - eventType: one of KEYBOARD_EVENT, BRAILLE_EVENT, MOUSE_BUTTON_EVENT
"""
self.type = eventType
+ 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 orca_state.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.
+ """
+
+ # 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):
+ orca_state.clickCount = 0
+ return
+
+ if not isinstance(lastInputEvent, KeyboardEvent):
+ orca_state.clickCount = 1
+ return
+
+ if self.time - lastInputEvent.time < settings.doubleClickTimeout:
+ # Cap the possible number of clicks at 3.
+ if orca_state.clickCount < 3:
+ orca_state.clickCount += 1
+ return
+
+ orca_state.clickCount = 1
+
class KeyboardEvent(InputEvent):
TYPE_UNKNOWN = "unknown"
@@ -222,22 +261,30 @@ class KeyboardEvent(InputEvent):
if self.keyType:
return self.keyType == KeyboardEvent.TYPE_MODIFIER
- modifierKeys = ['Alt_L', 'Alt_R', 'Control_L', 'Control_R',
- 'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R']
+ if self.isOrcaModifier():
+ return True
- if not orca_state.bypassNextCommand:
- orcaMods = settings.orcaModifierKeys
- try:
- orcaMods = map(lambda x: x.encode('UTF-8'), orcaMods)
- except (UnicodeDecodeError, UnicodeEncodeError):
- pass
- modifierKeys.extend(orcaMods)
+ return self.event_string in \
+ ['Alt_L', 'Alt_R', 'Control_L', 'Control_R',
+ 'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R']
+
+ def isOrcaModifier(self):
+ """Return True if this is the Orca modifier key."""
+
+ if orca_state.bypassNextCommand:
+ return False
+
+ orcaMods = settings.orcaModifierKeys
+ try:
+ orcaMods = map(lambda x: x.encode('UTF-8'), orcaMods)
+ except (UnicodeDecodeError, UnicodeEncodeError):
+ pass
string = self.event_string
if isinstance(string, unicode):
string = string.encode('UTF-8')
- return string in modifierKeys
+ return string in orcaMods
def isPrintableKey(self):
"""Return True if this is a printable key."""
@@ -257,6 +304,11 @@ class KeyboardEvent(InputEvent):
return unicodedata.category(unicodeString)[0] in ('P', 'S')
+ def isPressedKey(self):
+ """Returns True if the key is pressed"""
+
+ return self.type == pyatspi.KEY_PRESSED_EVENT
+
def isCharacterEchoable(self):
"""Returns True if the script will echo this event as part of
character echo. We do this to not double-echo a given printable
@@ -282,6 +334,71 @@ class KeyboardEvent(InputEvent):
return not self.modifiers & (1 << mod)
+ def getLockingStateString(self):
+ """Returns the string which reflects the locking state we wish to
+ include when presenting a locking key."""
+
+ locked = self.getLockingState()
+ if locked == None:
+ return ''
+
+ if not locked:
+ # Translators: This string is used to present the state of a
+ # locking key, such as Caps Lock. If Caps Lock is "off", then
+ # letters typed will appear in lowercase; if Caps Lock is "on",
+ # they will instead appear in uppercase. This string is also
+ # applied to Num Lock and potentially will be applied to similar
+ # keys in the future.
+ return C_("locking key state", "off")
+
+ # Translators: This string is used to present the state of a
+ # locking key, such as Caps Lock. If Caps Lock is "off", then
+ # letters typed will appear in lowercase; if Caps Lock is "on",
+ # they will instead appear in uppercase. This string is also
+ # applied to Num Lock and potentially will be applied to similar
+ # keys in the future.
+ return C_("locking key state", "on")
+
+ def getKeyName(self):
+ """Returns the string to be used for presenting the key to the user."""
+
+ return keynames.getKeyName(self.event_string)
+
+ def ignoreDueToTimestamp(self):
+ """Returns True if the event should be ignored due to its timestamp,
+ which might be completely absent or suggest that this input event is
+ a duplicate."""
+
+ if not self.timestamp:
+ return True
+ if self.timestamp != orca_state.lastInputEventTimestamp:
+ return False
+ if not orca_state.lastInputEvent:
+ return False
+ if self.hw_code == orca_state.lastInputEvent.hw_code \
+ and self.type == orca_state.lastInputEvent.type:
+ return True
+
+ return False
+
+ def present(self):
+ """Presents the event via the appropriate medium/media. Returns True
+ if we presented the event. False if there was some reason the event
+ was not worthy of presentation."""
+
+ if not self.shouldEcho:
+ return False
+
+ orca_state.lastKeyEchoTime = time.time()
+ debug.println(debug.LEVEL_FINEST,
+ "KeyboardEvent.present: %s" % self.event_string)
+
+ script = orca_state.activeScript
+ if script:
+ return script.presentKeyboardEvent(self)
+
+ return False
+
class BrailleEvent(InputEvent):
def __init__(self, event):
diff --git a/src/orca/keybindings.py b/src/orca/keybindings.py
index a57a9dc..b2bdb1d 100644
--- a/src/orca/keybindings.py
+++ b/src/orca/keybindings.py
@@ -31,7 +31,6 @@ from gi.repository import Gdk
import pyatspi
import debug
import settings
-import orca_state
from orca_i18n import _ # for gettext support
@@ -191,6 +190,24 @@ def getModifierNames(mods):
text += _("Shift") + "+"
return text
+def getClickCountString(count):
+ """Returns a human-consumable string representing the number of
+ clicks, such as 'double click' and 'triple click'."""
+
+ if count == 2:
+ # Translators: Orca keybindings support double
+ # and triple "clicks" or key presses, similar to
+ # using a mouse.
+ #
+ return _("double click")
+ if count == 3:
+ # Translators: Orca keybindings support double
+ # and triple "clicks" or key presses, similar to
+ # using a mouse.
+ #
+ return _("triple click")
+ return ""
+
class KeyBinding:
"""A single key binding, consisting of a keycode, a modifier mask,
and the InputEventHandler.
@@ -237,6 +254,26 @@ class KeyBinding:
else:
return False
+ def description(self):
+ """Returns the description of this binding's functionality."""
+
+ try:
+ return self.handler.description
+ except:
+ return ''
+
+ def asString(self, convertKeysym=False):
+ """Returns a more human-consumable string representing this binding."""
+
+ mods = getModifierNames(self.modifiers)
+ clickCount = getClickCountString(self.click_count)
+ keysym = self.keysymstring
+ if convertKeysym:
+ keysym = keysym.replace('KP_', _('keypad ')).title()
+ string = '%s%s %s' % (mods, keysym, clickCount)
+
+ return string.strip()
+
class KeyBindings:
"""Structure that maintains a set of KeyBinding instances.
"""
@@ -331,18 +368,35 @@ class KeyBindings:
return hasIt
+ def getBoundBindings(self, uniqueOnly=False):
+ """Returns the KeyBinding instances which are bound to a keystroke.
+
+ Arguments:
+ - uniqueOnly: Should alternative bindings for the same handler be
+ filtered out (default: False)
+ """
+
+ bound = filter(lambda kb: kb.keysymstring, self.keyBindings)
+ if uniqueOnly:
+ handlers = [kb.handler.description for kb in bound]
+ bound = [bound[i] for i in map(handlers.index, set(handlers))]
+
+ return bound
+
+ def getBindingsForHandler(self, handler):
+ """Returns the KeyBinding instances associated with handler."""
+
+ return filter(lambda kb: kb.handler == handler, self.keyBindings)
+
def getInputHandler(self, keyboardEvent):
"""Returns the input handler of the key binding that matches the
given keycode and modifiers, or None if no match exists.
"""
- if not orca_state.activeScript:
- return None
-
candidates = []
- clickCount = orca_state.activeScript.getClickCount()
+ clickCount = keyboardEvent.getClickCount()
for keyBinding in self.keyBindings:
- if keyBinding.matches(keyboardEvent.hw_code, \
+ if keyBinding.matches(keyboardEvent.hw_code,
keyboardEvent.modifiers):
if keyBinding.modifier_mask == keyboardEvent.modifiers and \
keyBinding.click_count == clickCount:
diff --git a/src/orca/scripts/default.py b/src/orca/scripts/default.py
index 91c5227..72cac51 100644
--- a/src/orca/scripts/default.py
+++ b/src/orca/scripts/default.py
@@ -5359,6 +5359,31 @@ class Script(script.Script):
# #
############################################################################
+ def presentationInterrupt(self):
+ """Convenience method to interrupt presentation of whatever is being
+ presented at the moment."""
+
+ speech.stop()
+ braille.killFlash()
+
+ def presentKeyboardEvent(self, event):
+ """Convenience method to present the KeyboardEvent event. Returns True
+ if we fully present the event; False otherwise."""
+
+ braille.displayKeyEvent(event)
+
+ orcaModifierPressed = event.isOrcaModifier() and event.isPressedKey()
+ if event.isCharacterEchoable() and not orcaModifierPressed:
+ return False
+
+ if orca_state.learnModeEnabled:
+ if event.isPrintableKey() and event.getClickCount() == 2:
+ self.phoneticSpellCurrentItem(event.event_string)
+ return True
+
+ speech.speakKeyEvent(event)
+ return True
+
def presentMessage(self, fullMessage, briefMessage=None, voice=None):
"""Convenience method to speak a message and 'flash' it in braille.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]