[orca: 1/2] keyboard: add support for ShiftLock



commit 496ea5167971cb8b2a3f0af6c5f4353181d965ef
Author: Samuel Thibault <samuel thibault ens-lyon org>
Date:   Mon Aug 6 14:38:49 2018 +0200

    keyboard: add support for ShiftLock
    
    For people using the xkb caps:shiftlock option
    
    Fixes #10

 src/orca/input_event.py           | 18 +++++++++++----
 src/orca/keybindings.py           | 10 ++++++++
 src/orca/keynames.py              |  5 ++++
 src/orca/orca-setup.ui            |  2 +-
 src/orca/orca.py                  | 48 +++++++++++++++++++++++++++------------
 src/orca/orca_gui_prefs.py        |  9 +++++++-
 src/orca/settings.py              |  2 +-
 test/harness/generalSettings.conf |  2 +-
 8 files changed, 74 insertions(+), 22 deletions(-)
---
diff --git a/src/orca/input_event.py b/src/orca/input_event.py
index dfe93a68f..d96343db6 100644
--- a/src/orca/input_event.py
+++ b/src/orca/input_event.py
@@ -350,7 +350,7 @@ class KeyboardEvent(InputEvent):
         if self.keyType:
             return self.keyType in KeyboardEvent.TYPE_LOCKING
 
-        lockingKeys = ["Caps_Lock", "Num_Lock", "Scroll_Lock"]
+        lockingKeys = ["Caps_Lock", "Shift_Lock", "Num_Lock", "Scroll_Lock"]
         if not self.event_string in lockingKeys:
             return False
 
@@ -470,6 +470,8 @@ class KeyboardEvent(InputEvent):
 
         if self.event_string == "Caps_Lock":
             mod = pyatspi.MODIFIER_SHIFTLOCK
+        elif self.event_string == "Shift_Lock":
+            mod = pyatspi.MODIFIER_SHIFT
         elif self.event_string == "Num_Lock":
             mod = pyatspi.MODIFIER_NUMLOCK
         else:
@@ -649,6 +651,7 @@ class KeyboardEvent(InputEvent):
 
         if self._bypassOrca:
             if self.event_string == "Caps_Lock" \
+               or self.event_string == "Shift_Lock" \
                and self.type == pyatspi.KEY_PRESSED_EVENT:
                     self._lock_mod()
                     self.keyType = KeyboardEvent.TYPE_LOCKING
@@ -694,10 +697,9 @@ class KeyboardEvent(InputEvent):
         return False, 'Unaddressed case'
 
     def _lock_mod(self):
-        def lock_mod(modifiers):
+        def lock_mod(modifiers, modifier):
             def lockit():
                 try:
-                    modifier = (1 << pyatspi.MODIFIER_SHIFTLOCK)
                     if modifiers & modifier:
                         lock = pyatspi.KEY_UNLOCKMODIFIERS
                         debug.println(debug.LEVEL_INFO, "Locking capslock", True)
@@ -711,8 +713,16 @@ class KeyboardEvent(InputEvent):
                         "at-spi2-core >= 2.30 is needed for triggering capslock", True)
                     pass
             return lockit
+        if self.event_string == "Caps_Lock":
+            modifier = 1 << pyatspi.MODIFIER_SHIFTLOCK
+        elif self.event_string == "Shift_Lock":
+            modifier = 1 << pyatspi.MODIFIER_SHIFT
+        else:
+            msg = "Unknown locking key %s" % self.event_string
+            debug.println(debug.LEVEL_WARNING, msg, False)
+            return
         debug.println(debug.LEVEL_INFO, "Scheduling capslock", True)
-        GLib.timeout_add(1, lock_mod(self.modifiers))
+        GLib.timeout_add(1, lock_mod(self.modifiers, modifier))
 
     def _consume(self):
         startTime = time.time()
diff --git a/src/orca/keybindings.py b/src/orca/keybindings.py
index 5bb5dfba0..ff471ef05 100644
--- a/src/orca/keybindings.py
+++ b/src/orca/keybindings.py
@@ -131,6 +131,10 @@ def getModifierNames(mods):
     """Gets the modifier names of a numeric modifier mask as a human
     consumable string.
     """
+    try:
+        shiftmask = 1 << pyatspi.MODIFIER_SHIFT
+    except:
+        shiftmask = 0
 
     text = ""
     if mods & ORCA_MODIFIER_MASK:
@@ -147,6 +151,12 @@ def getModifierNames(mods):
         # "caps lock" modifier.
         #
         text += _("Caps_Lock") + "+"
+    elif mods & shiftmask:
+        # Translators: this is presented in a GUI to represent the
+        # "shift lock" modifier. There is no reason to make it different from
+        # the translation for "Caps_Lock"
+        #
+        text += _("Shift_Lock") + "+"
     #if mods & (1 << pyatspi.MODIFIER_NUMLOCK):
     #    text += _("Num_Lock") + "+"
     if mods & 128:
diff --git a/src/orca/keynames.py b/src/orca/keynames.py
index d72c774f6..4e4f9318d 100644
--- a/src/orca/keynames.py
+++ b/src/orca/keynames.py
@@ -89,6 +89,11 @@ __keynames["Num_Lock"]     = _("num lock")
 #
 __keynames["Caps_Lock"]    = _("caps lock")
 
+# Translators: this is how someone would speak the name of the shift lock key
+# There is no reason to make it different from the translation for "caps lock"
+#
+__keynames["Shift_Lock"]    = _("shift lock")
+
 # Translators: this is how someone would speak the name of the scroll lock key
 #
 __keynames["Scroll_Lock"]  = _("scroll lock")
diff --git a/src/orca/orca-setup.ui b/src/orca/orca-setup.ui
index 9995f20a7..98aa22b62 100644
--- a/src/orca/orca-setup.ui
+++ b/src/orca/orca-setup.ui
@@ -86,7 +86,7 @@
         <col id="0">Insert</col>
       </row>
       <row>
-        <col id="0">Caps_Lock</col>
+        <col id="0">Caps_Lock, Shift_Lock</col>
       </row>
     </data>
   </object>
diff --git a/src/orca/orca.py b/src/orca/orca.py
index 9d5789d24..33b7532aa 100644
--- a/src/orca/orca.py
+++ b/src/orca/orca.py
@@ -248,32 +248,51 @@ def _setCapsLockAsOrcaModifier(enable):
     """Enable or disable use of the caps lock key as an Orca modifier key."""
     interpretCapsLineProg = re.compile(
         r'^\s*interpret\s+Caps[_+]Lock[_+]AnyOfOrNone\s*\(all\)\s*{\s*$', re.I)
-    capsModLineProg = re.compile(
-        r'^\s*action\s*=\s*NoAction\s*\(\s*\)\s*;\s*$', re.I)
     normalCapsLineProg = re.compile(
         r'^\s*action\s*=\s*LockMods\s*\(\s*modifiers\s*=\s*Lock\s*\)\s*;\s*$', re.I)
+    interpretShiftLineProg = re.compile(
+        r'^\s*interpret\s+Shift[_+]Lock[_+]AnyOf\s*\(\s*Shift\s*\+\s*Lock\s*\)\s*{\s*$', re.I)
+    normalShiftLineProg = re.compile(
+        r'^\s*action\s*=\s*LockMods\s*\(\s*modifiers\s*=\s*Shift\s*\)\s*;\s*$', re.I)
+    disabledModLineProg = re.compile(
+        r'^\s*action\s*=\s*NoAction\s*\(\s*\)\s*;\s*$', re.I)
     normalCapsLine = '        action= LockMods(modifiers=Lock);'
-    capsModLine =    '        action= NoAction();'
+    normalShiftLine = '        action= LockMods(modifiers=Shift);'
+    disabledModLine = '        action= NoAction();'
     lines = _originalXmodmap.decode('UTF-8').split('\n')
     foundCapsInterpretSection = False
+    foundShiftInterpretSection = False
+    modified = False
     for i, line in enumerate(lines):
-        if not foundCapsInterpretSection:
+        if not foundCapsInterpretSection and not foundShiftInterpretSection:
             if interpretCapsLineProg.match(line):
                 foundCapsInterpretSection = True
-        else:
+            elif interpretShiftLineProg.match(line):
+                foundShiftInterpretSection = True
+        elif foundCapsInterpretSection:
             if enable:
                 if normalCapsLineProg.match(line):
-                    lines[i] = capsModLine
-                    _setXmodmap(bytes('\n'.join(lines), 'UTF-8'))
-                    return
+                    lines[i] = disabledModLine
+                    modified = True
             else:
-                if capsModLineProg.match(line):
+                if disabledModLineProg.match(line):
                     lines[i] = normalCapsLine
-                    _setXmodmap(bytes('\n'.join(lines), 'UTF-8'))
-                    return
+                    modified = True
+            if line.find('}'):
+                foundCapsInterpretSection = False
+        else: # foundShiftInterpretSection
+            if enable:
+                if normalShiftLineProg.match(line):
+                    lines[i] = disabledModLine
+                    modified = True
+            else:
+                if disabledModLineProg.match(line):
+                    lines[i] = normalShiftLine
+                    modified = True
             if line.find('}'):
-                # Failed to find the line we need to change
-                return
+                foundShiftInterpretSection = False
+    if modified:
+        _setXmodmap(bytes('\n'.join(lines), 'UTF-8'))
 
 def _createOrcaXmodmap():
     """Makes an Orca-specific Xmodmap so that the keys behave as we
@@ -283,7 +302,8 @@ def _createOrcaXmodmap():
     global _capsLockCleared
 
     cmd = []
-    if "Caps_Lock" in settings.orcaModifierKeys:
+    if "Caps_Lock" in settings.orcaModifierKeys \
+       or "Shift_Lock" in settings.orcaModifierKeys:
         _setCapsLockAsOrcaModifier(True)
         _capsLockCleared = True
     elif _capsLockCleared:
diff --git a/src/orca/orca_gui_prefs.py b/src/orca/orca_gui_prefs.py
index d2167cf00..4866c19ea 100644
--- a/src/orca/orca_gui_prefs.py
+++ b/src/orca/orca_gui_prefs.py
@@ -2642,7 +2642,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
 
         modifierKeys =  ['Alt_L', 'Alt_R', 'Control_L', 'Control_R',
                          'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R',
-                         'Num_Lock', 'Caps_Lock']
+                         'Num_Lock', 'Caps_Lock', 'Shift_Lock']
         if eventString in modifierKeys:
             return False
 
@@ -2743,6 +2743,13 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
         if mods & (1 << pyatspi.MODIFIER_SHIFTLOCK) \
            and mods & keybindings.ORCA_MODIFIER_MASK:
             mods ^= (1 << pyatspi.MODIFIER_SHIFTLOCK)
+        try:
+            shiftmask = (1 << pyatspi.MODIFIER_SHIFT)
+        except:
+            shiftmask = 0
+        if mods & shiftmask \
+           and mods & keybindings.ORCA_MODIFIER_MASK:
+            mods ^= (1 << pyatspi.MODIFIER_SHIFT)
 
         treeModel.set(myiter,
                       modMask, str(keybindings.defaultModifierMask),
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 2974ab29a..ccb728ec1 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -149,7 +149,7 @@ GENERAL_KEYBOARD_LAYOUT_DESKTOP = 1
 GENERAL_KEYBOARD_LAYOUT_LAPTOP  = 2
 
 DESKTOP_MODIFIER_KEYS = ["Insert", "KP_Insert"]
-LAPTOP_MODIFIER_KEYS  = ["Caps_Lock"]
+LAPTOP_MODIFIER_KEYS  = ["Caps_Lock", "Shift_Lock"]
 
 VERBOSITY_LEVEL_BRIEF   = 0
 VERBOSITY_LEVEL_VERBOSE = 1
diff --git a/test/harness/generalSettings.conf b/test/harness/generalSettings.conf
index 0e5333b88..edfcdd41f 100644
--- a/test/harness/generalSettings.conf
+++ b/test/harness/generalSettings.conf
@@ -2,7 +2,7 @@
  "keyboardLayout": 2,
  "magSourceDisplay": ":0.0",
  "magTargetDisplay": ":0.0",
- "orcaModifierKeys": ["Caps_Lock"],
+ "orcaModifierKeys": ["Caps_Lock, Shift_Lock"],
  "profile": ["Laptop", "laptop"],
  "quitOrcaNoConfirmation": true,
  "speechServerFactory": "orca.speechdispatcherfactory",


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