On 10/20/2013 3:55 PM, Alex Midence
wrote:
I have implemented a quick solution that is working well for me. I am now able to completely control my remote Ubuntu desktop with Orca over VNC, though when things go wrong, I still have decent vision to deal with it. I suspect this hack may be useful to others. What I did was add two special keys to Orca. The first is an "Orca shift" key. Orca shift is enabled when I press left shift and release it, and it causes the next keyboard event to have the Orca modifier. For example, if I press and release left shift, and then space, Orca's preferences dialog comes up. The second is an "Orca lock" key. Orca lock is toggled when I press right control and release it, and it causes all keyboard events to have the orca modifier until I ether press the Orca lock key again, or the orca shift key. Here's the code I modified. It's the keyboard event handler in orca.py. A proper implementation should allow the user to select the modifier keys to use as Orca Shift and Orca Lock, but I just hard-coded it for now. If there's interest in having this feature become part of Orca, I'll check out the latest Orca code and submit a patch that is similar to this code, but which has user settings to determine the modifier keys used, and which by default are off. This would allow users to enable Orca Shift and Orca Lock by editing their user-settings.py file. What do you guys think? ######################################################################## # # # METHODS FOR PRE-PROCESSING AND MASSAGING KEYBOARD EVENTS. # # # ######################################################################## _orcaModifierPressed = False # Bill: I added these four globals to track the state of Orca Lock and Orca Shift _orcaKeyLocked = False _nextKeyHasOrcaModifier = False _lastWasOrcaLockDown = False _lastWasOrcaShiftDown = 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 global _orcaKeyLocked global _nextKeyHasOrcaModifier global _lastWasOrcaLockDown global _lastWasOrcaShiftDown # Weed out duplicate and otherwise bogus events. keyboardEvent = KeyboardEvent(event) debug.println(debug.LEVEL_FINE, keyboardEvent.toString()) if keyboardEvent.ignoreDueToTimestamp(): debug.println(debug.LEVEL_FINE, "IGNORING EVENT DUE TO TIMESTAMP") return # Figure out what we've got. isOrcaModifier = keyboardEvent.isOrcaModifier() isPressedEvent = keyboardEvent.isPressedKey() if isOrcaModifier: _orcaModifierPressed = isPressedEvent # Bill: I added the Orca Lock and Orca Shift conditions to this if statement if _orcaModifierPressed or _orcaKeyLocked or _nextKeyHasOrcaModifier: keyboardEvent.modifiers |= settings.ORCA_MODIFIER_MASK # Update our state. orca_state.lastInputEventTimestamp = event.timestamp orca_state.lastInputEvent = keyboardEvent # Bill: Deal with Orca key lock event if keyboardEvent.keyval_name == "Control_R": if isPressedEvent: _lastWasOrcaLockDown = True else: if _lastWasOrcaLockDown: _orcaKeyLocked = not _orcaKeyLocked _nextKeyHasOrcaModifier = False _lastWasOrcaLockDown = False else: _lastWasOrcaLockDown = False # Bill: Deal with Orca key shift event if keyboardEvent.keyval_name == "Shift_L": if isPressedEvent: _lastWasOrcaShiftDown = True _orcaKeyLocked = False else: if _lastWasOrcaShiftDown: _nextKeyHasOrcaModifier = True _lastWasOrcaShiftDown = False else: _lastWasOrcaShiftDown = False _nextKeyHasOrcaModifier = False 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 script: if isPressedEvent: script.presentationInterrupt() keyboardEvent.present() if keyboardEvent.isModifierKey() and not isOrcaModifier: return False # 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 keyboardEvent.event_string in ["1", "2"]: orca_state.learnModeEnabled = False return script.listOrcaShortcuts(keyboardEvent) if orca_state.capturingKeys: return False if notification_messages.listNotificationMessagesModeEnabled: return notification_messages.listNotificationMessages(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 |