[orca] Begin refactoring of keyboard event processing
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Begin refactoring of keyboard event processing
- Date: Mon, 4 Apr 2016 22:10:31 +0000 (UTC)
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]