Attempt to handle capslock as modifier better.
This commit is contained in:
+5
-141
@@ -186,9 +186,7 @@ class APIHelper:
|
|||||||
import gi
|
import gi
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
gi.require_version("Atspi", "2.0")
|
gi.require_version("Atspi", "2.0")
|
||||||
@@ -212,6 +210,7 @@ from . import logger
|
|||||||
from . import messages
|
from . import messages
|
||||||
from . import notification_presenter
|
from . import notification_presenter
|
||||||
from . import focus_manager
|
from . import focus_manager
|
||||||
|
from . import cthulhu_modifier_manager
|
||||||
from . import cthulhu_state
|
from . import cthulhu_state
|
||||||
from . import cthulhu_platform
|
from . import cthulhu_platform
|
||||||
from . import script_manager
|
from . import script_manager
|
||||||
@@ -280,14 +279,6 @@ EXIT_CODE_HANG = 50
|
|||||||
#
|
#
|
||||||
_userSettings = None
|
_userSettings = None
|
||||||
|
|
||||||
# A subset of the original Xmodmap info prior to our stomping on it.
|
|
||||||
# Right now, this is just for the user's chosen Cthulhu modifier(s).
|
|
||||||
#
|
|
||||||
_originalXmodmap = ""
|
|
||||||
_cthulhuModifiers = settings.DESKTOP_MODIFIER_KEYS + settings.LAPTOP_MODIFIER_KEYS
|
|
||||||
_capsLockCleared = False
|
|
||||||
_restoreCthulhuKeys = False
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# #
|
# #
|
||||||
# METHODS TO HANDLE APPLICATION LIST AND FOCUSED OBJECTS #
|
# METHODS TO HANDLE APPLICATION LIST AND FOCUSED OBJECTS #
|
||||||
@@ -382,125 +373,7 @@ def deviceChangeHandler(deviceManager, device):
|
|||||||
if source == Gdk.InputSource.KEYBOARD:
|
if source == Gdk.InputSource.KEYBOARD:
|
||||||
msg = "CTHULHU: Keyboard change detected, re-creating the xmodmap"
|
msg = "CTHULHU: Keyboard change detected, re-creating the xmodmap"
|
||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
_createCthulhuXmodmap()
|
cthulhu_modifier_manager.getManager().refreshCthulhuModifiers("Keyboard change detected.")
|
||||||
|
|
||||||
def updateKeyMap(keyboardEvent):
|
|
||||||
"""Unsupported convenience method to call sad hacks which should go away."""
|
|
||||||
|
|
||||||
global _restoreCthulhuKeys
|
|
||||||
if keyboardEvent.is_pressed_key():
|
|
||||||
return
|
|
||||||
|
|
||||||
if keyboardEvent.event_string in settings.cthulhuModifierKeys \
|
|
||||||
and cthulhu_state.bypassNextCommand:
|
|
||||||
_restoreXmodmap()
|
|
||||||
_restoreCthulhuKeys = True
|
|
||||||
return
|
|
||||||
|
|
||||||
if _restoreCthulhuKeys and not cthulhu_state.bypassNextCommand:
|
|
||||||
_createCthulhuXmodmap()
|
|
||||||
_restoreCthulhuKeys = False
|
|
||||||
|
|
||||||
def _setXmodmap(xkbmap):
|
|
||||||
"""Set the keyboard map using xkbcomp."""
|
|
||||||
p = subprocess.Popen(['xkbcomp', '-w0', '-', os.environ['DISPLAY']],
|
|
||||||
stdin=subprocess.PIPE, stdout=None, stderr=None)
|
|
||||||
p.communicate(xkbmap)
|
|
||||||
|
|
||||||
def _setCapsLockAsCthulhuModifier(enable):
|
|
||||||
"""Enable or disable use of the caps lock key as an Cthulhu modifier key."""
|
|
||||||
interpretCapsLineProg = re.compile(
|
|
||||||
r'^\s*interpret\s+Caps[_+]Lock[_+]AnyOfOrNone\s*\(all\)\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);'
|
|
||||||
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 and not foundShiftInterpretSection:
|
|
||||||
if interpretCapsLineProg.match(line):
|
|
||||||
foundCapsInterpretSection = True
|
|
||||||
elif interpretShiftLineProg.match(line):
|
|
||||||
foundShiftInterpretSection = True
|
|
||||||
elif foundCapsInterpretSection:
|
|
||||||
if enable:
|
|
||||||
if normalCapsLineProg.match(line):
|
|
||||||
lines[i] = disabledModLine
|
|
||||||
modified = True
|
|
||||||
else:
|
|
||||||
if disabledModLineProg.match(line):
|
|
||||||
lines[i] = normalCapsLine
|
|
||||||
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('}'):
|
|
||||||
foundShiftInterpretSection = False
|
|
||||||
if modified:
|
|
||||||
_setXmodmap(bytes('\n'.join(lines), 'UTF-8'))
|
|
||||||
|
|
||||||
def _createCthulhuXmodmap():
|
|
||||||
"""Makes an Cthulhu-specific Xmodmap so that the keys behave as we
|
|
||||||
need them to do. This is especially the case for the Cthulhu modifier.
|
|
||||||
"""
|
|
||||||
|
|
||||||
global _capsLockCleared
|
|
||||||
|
|
||||||
if "Caps_Lock" in settings.cthulhuModifierKeys \
|
|
||||||
or "Shift_Lock" in settings.cthulhuModifierKeys:
|
|
||||||
_setCapsLockAsCthulhuModifier(True)
|
|
||||||
_capsLockCleared = True
|
|
||||||
elif _capsLockCleared:
|
|
||||||
_setCapsLockAsCthulhuModifier(False)
|
|
||||||
_capsLockCleared = False
|
|
||||||
|
|
||||||
def _storeXmodmap(keyList):
|
|
||||||
"""Save the original xmodmap for the keys in keyList before we alter it.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
- keyList: A list of named keys to look for.
|
|
||||||
"""
|
|
||||||
|
|
||||||
global _originalXmodmap
|
|
||||||
_originalXmodmap = subprocess.check_output(['xkbcomp', os.environ['DISPLAY'], '-'])
|
|
||||||
|
|
||||||
def _restoreXmodmap(keyList=[]):
|
|
||||||
"""Restore the original xmodmap values for the keys in keyList.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
- keyList: A list of named keys to look for. An empty list means
|
|
||||||
to restore the entire saved xmodmap.
|
|
||||||
"""
|
|
||||||
|
|
||||||
msg = "CTHULHU: Attempting to restore original xmodmap"
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
|
||||||
|
|
||||||
global _capsLockCleared
|
|
||||||
_capsLockCleared = False
|
|
||||||
p = subprocess.Popen(['xkbcomp', '-w0', '-', os.environ['DISPLAY']],
|
|
||||||
stdin=subprocess.PIPE, stdout=None, stderr=None)
|
|
||||||
p.communicate(_originalXmodmap)
|
|
||||||
|
|
||||||
msg = "CTHULHU: Original xmodmap restored"
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
|
||||||
|
|
||||||
def setKeyHandling(new):
|
def setKeyHandling(new):
|
||||||
"""Toggle use of the new vs. legacy key handling mode.
|
"""Toggle use of the new vs. legacy key handling mode.
|
||||||
@@ -588,16 +461,7 @@ def loadUserSettings(script=None, inputEvent=None, skipReloadMessage=False):
|
|||||||
if _settingsManager.getSetting('enableSound'):
|
if _settingsManager.getSetting('enableSound'):
|
||||||
player.init()
|
player.init()
|
||||||
|
|
||||||
global _cthulhuModifiers
|
cthulhu_modifier_manager.getManager().refreshCthulhuModifiers("Loading user settings.")
|
||||||
custom = [k for k in settings.cthulhuModifierKeys if k not in _cthulhuModifiers]
|
|
||||||
_cthulhuModifiers += custom
|
|
||||||
# Handle the case where a change was made in the Cthulhu Preferences dialog.
|
|
||||||
#
|
|
||||||
if _originalXmodmap:
|
|
||||||
_restoreXmodmap(_cthulhuModifiers)
|
|
||||||
|
|
||||||
_storeXmodmap(_cthulhuModifiers)
|
|
||||||
_createCthulhuXmodmap()
|
|
||||||
|
|
||||||
# Activate core systems FIRST before loading plugins
|
# Activate core systems FIRST before loading plugins
|
||||||
_scriptManager.activate()
|
_scriptManager.activate()
|
||||||
@@ -894,7 +758,7 @@ def shutdown(script=None, inputEvent=None):
|
|||||||
signal.alarm(0)
|
signal.alarm(0)
|
||||||
|
|
||||||
_initialized = False
|
_initialized = False
|
||||||
_restoreXmodmap(_cthulhuModifiers)
|
cthulhu_modifier_manager.getManager().unsetCthulhuModifiers("Shutting down.")
|
||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, 'CTHULHU: Quitting Atspi main event loop', True)
|
debug.printMessage(debug.LEVEL_INFO, 'CTHULHU: Quitting Atspi main event loop', True)
|
||||||
Atspi.event_quit()
|
Atspi.event_quit()
|
||||||
@@ -948,7 +812,7 @@ def crashOnSignal(signum, frame):
|
|||||||
msg = f"CTHULHU: Shutting down and exiting due to signal={signum} {signalString}"
|
msg = f"CTHULHU: Shutting down and exiting due to signal={signum} {signalString}"
|
||||||
debug.printMessage(debug.LEVEL_SEVERE, msg, True)
|
debug.printMessage(debug.LEVEL_SEVERE, msg, True)
|
||||||
debug.printStack(debug.LEVEL_SEVERE)
|
debug.printStack(debug.LEVEL_SEVERE)
|
||||||
_restoreXmodmap(_cthulhuModifiers)
|
cthulhu_modifier_manager.getManager().unsetCthulhuModifiers("Crashed")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2026 Stormux
|
||||||
|
# Copyright (c) 2023 Igalia, S.L.
|
||||||
|
# Author: Joanmarie Diggs <jdiggs@igalia.com>
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the
|
||||||
|
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
|
||||||
|
# Boston MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Forked from Orca screen reader.
|
||||||
|
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
||||||
|
|
||||||
|
"""Manages the Cthulhu modifier key(s)."""
|
||||||
|
|
||||||
|
__id__ = "$Id$"
|
||||||
|
__version__ = "$Revision$"
|
||||||
|
__date__ = "$Date$"
|
||||||
|
__copyright__ = "Copyright (c) 2026 Stormux"
|
||||||
|
__license__ = "LGPL"
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import gi
|
||||||
|
gi.require_version("Atspi", "2.0")
|
||||||
|
from gi.repository import Atspi
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
import cthulhu.debug as debug
|
||||||
|
import cthulhu.settings as settings
|
||||||
|
|
||||||
|
class CthulhuModifierManager:
|
||||||
|
"""Manages the Cthulhu modifier."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._originalXmodmap = b""
|
||||||
|
self._capsLockCleared = False
|
||||||
|
|
||||||
|
def refreshCthulhuModifiers(self, reason=""):
|
||||||
|
"""Refreshes the Cthulhu modifier keys."""
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Refreshing Cthulhu modifiers"
|
||||||
|
if reason:
|
||||||
|
msg += f": {reason}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
display = os.environ.get("DISPLAY")
|
||||||
|
if not display:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: DISPLAY not set, skipping xkbcomp operations"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.unsetCthulhuModifiers(reason)
|
||||||
|
with subprocess.Popen(["xkbcomp", display, "-"],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) as process:
|
||||||
|
self._originalXmodmap, _ = process.communicate()
|
||||||
|
self._createCthulhuXmodmap()
|
||||||
|
|
||||||
|
def unsetCthulhuModifiers(self, reason=""):
|
||||||
|
"""Turns the Cthulhu modifiers back into their original purpose."""
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Attempting to restore original xmodmap"
|
||||||
|
if reason:
|
||||||
|
msg += f": {reason}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
if not self._originalXmodmap:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: No stored xmodmap found"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
display = os.environ.get("DISPLAY")
|
||||||
|
if not display:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: DISPLAY not set, skipping xmodmap restoration"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._capsLockCleared = False
|
||||||
|
with subprocess.Popen(["xkbcomp", "-w0", "-", display],
|
||||||
|
stdin=subprocess.PIPE, stdout=None, stderr=None) as process:
|
||||||
|
process.communicate(self._originalXmodmap)
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Original xmodmap restored"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
def _createCthulhuXmodmap(self):
|
||||||
|
"""Makes a Cthulhu-specific Xmodmap so that the modifier works."""
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Creating Cthulhu xmodmap"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
if "Caps_Lock" in settings.cthulhuModifierKeys \
|
||||||
|
or "Shift_Lock" in settings.cthulhuModifierKeys:
|
||||||
|
self.setCapsLockAsCthulhuModifier(True)
|
||||||
|
self._capsLockCleared = True
|
||||||
|
elif self._capsLockCleared:
|
||||||
|
self.setCapsLockAsCthulhuModifier(False)
|
||||||
|
self._capsLockCleared = False
|
||||||
|
|
||||||
|
def setCapsLockAsCthulhuModifier(self, enable):
|
||||||
|
"""Enable or disable use of the caps lock key as a Cthulhu modifier key."""
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Setting caps lock as the Cthulhu modifier"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
display = os.environ.get("DISPLAY")
|
||||||
|
if not display:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: DISPLAY not set, cannot modify caps lock"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self._originalXmodmap:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: No xmodmap available, cannot modify caps lock"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
return
|
||||||
|
|
||||||
|
interpretCapsLineProg = re.compile(
|
||||||
|
r'^\s*interpret\s+Caps[_+]Lock[_+]AnyOfOrNone\s*\(all\)\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);'
|
||||||
|
normalShiftLine = ' action= LockMods(modifiers=Shift);'
|
||||||
|
disabledModLine = ' action= NoAction();'
|
||||||
|
lines = self._originalXmodmap.decode('UTF-8').split('\n')
|
||||||
|
foundCapsInterpretSection = False
|
||||||
|
foundShiftInterpretSection = False
|
||||||
|
modified = False
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if not foundCapsInterpretSection and not foundShiftInterpretSection:
|
||||||
|
if interpretCapsLineProg.match(line):
|
||||||
|
foundCapsInterpretSection = True
|
||||||
|
elif interpretShiftLineProg.match(line):
|
||||||
|
foundShiftInterpretSection = True
|
||||||
|
elif foundCapsInterpretSection:
|
||||||
|
if enable:
|
||||||
|
if normalCapsLineProg.match(line):
|
||||||
|
lines[i] = disabledModLine
|
||||||
|
modified = True
|
||||||
|
else:
|
||||||
|
if disabledModLineProg.match(line):
|
||||||
|
lines[i] = normalCapsLine
|
||||||
|
modified = True
|
||||||
|
if line.find('}'):
|
||||||
|
foundCapsInterpretSection = False
|
||||||
|
elif 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('}'):
|
||||||
|
foundShiftInterpretSection = False
|
||||||
|
if modified:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Updating xmodmap"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
with subprocess.Popen(["xkbcomp", "-w0", "-", display],
|
||||||
|
stdin=subprocess.PIPE, stdout=None, stderr=None) as process:
|
||||||
|
process.communicate(bytes('\n'.join(lines), 'UTF-8'))
|
||||||
|
else:
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Not updating xmodmap"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
def toggleModifier(self, keyboardEvent):
|
||||||
|
"""Toggles the modifier to enable double-clicking causing normal behavior."""
|
||||||
|
|
||||||
|
if keyboardEvent.keyval_name in ["Caps_Lock", "Shift_Lock"]:
|
||||||
|
self._toggleModifierLock(keyboardEvent)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _toggleModifierLock(self, keyboardEvent):
|
||||||
|
"""Toggles the lock for a modifier to enable double-clicking causing normal behavior."""
|
||||||
|
|
||||||
|
if not keyboardEvent.is_pressed_key():
|
||||||
|
return
|
||||||
|
|
||||||
|
def toggle(modifiers, modifier):
|
||||||
|
if modifiers & modifier:
|
||||||
|
lock = Atspi.KeySynthType.UNLOCKMODIFIERS
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Unlocking CapsLock"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
else:
|
||||||
|
lock = Atspi.KeySynthType.LOCKMODIFIERS
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Locking CapsLock"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
Atspi.generate_keyboard_event(modifier, "", lock)
|
||||||
|
|
||||||
|
if keyboardEvent.keyval_name == "Caps_Lock":
|
||||||
|
modifier = 1 << Atspi.ModifierType.SHIFTLOCK
|
||||||
|
elif keyboardEvent.keyval_name == "Shift_Lock":
|
||||||
|
modifier = 1 << Atspi.ModifierType.SHIFT
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
msg = "CTHULHU MODIFIER MANAGER: Scheduling lock change"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
GLib.timeout_add(1, toggle, keyboardEvent.modifiers, modifier)
|
||||||
|
|
||||||
|
_manager = CthulhuModifierManager()
|
||||||
|
|
||||||
|
def getManager():
|
||||||
|
"""Returns the CthulhuModifierManager singleton."""
|
||||||
|
return _manager
|
||||||
@@ -47,6 +47,7 @@ from . import keybindings
|
|||||||
from . import keynames
|
from . import keynames
|
||||||
from . import messages
|
from . import messages
|
||||||
from . import cthulhu
|
from . import cthulhu
|
||||||
|
from . import cthulhu_modifier_manager
|
||||||
from . import cthulhu_state
|
from . import cthulhu_state
|
||||||
from . import script_manager
|
from . import script_manager
|
||||||
from . import settings
|
from . import settings
|
||||||
@@ -347,7 +348,10 @@ class KeyboardEvent(InputEvent):
|
|||||||
KeyboardEvent.secondCthulhuModifierTime <
|
KeyboardEvent.secondCthulhuModifierTime <
|
||||||
KeyboardEvent.lastCthulhuModifierAloneTime + 0.5):
|
KeyboardEvent.lastCthulhuModifierAloneTime + 0.5):
|
||||||
# double-cthulhu, let the real action happen
|
# double-cthulhu, let the real action happen
|
||||||
self._bypassCthulhu = True
|
if self.event_string in ["Caps_Lock", "Shift_Lock"]:
|
||||||
|
cthulhu_modifier_manager.getManager().toggleModifier(self)
|
||||||
|
else:
|
||||||
|
self._bypassCthulhu = True
|
||||||
if not _isPressed:
|
if not _isPressed:
|
||||||
KeyboardEvent.lastCthulhuModifierAlone = False
|
KeyboardEvent.lastCthulhuModifierAlone = False
|
||||||
KeyboardEvent.lastCthulhuModifierAloneTime = False
|
KeyboardEvent.lastCthulhuModifierAloneTime = False
|
||||||
@@ -955,7 +959,6 @@ class KeyboardEvent(InputEvent):
|
|||||||
if (self.event_string == "Caps_Lock" \
|
if (self.event_string == "Caps_Lock" \
|
||||||
or self.event_string == "Shift_Lock") \
|
or self.event_string == "Shift_Lock") \
|
||||||
and self.type == Atspi.EventType.KEY_PRESSED_EVENT:
|
and self.type == Atspi.EventType.KEY_PRESSED_EVENT:
|
||||||
self._lock_mod()
|
|
||||||
self.keyType = KeyboardEvent.TYPE_LOCKING
|
self.keyType = KeyboardEvent.TYPE_LOCKING
|
||||||
self._present()
|
self._present()
|
||||||
return False, 'Bypassed cthulhu modifier'
|
return False, 'Bypassed cthulhu modifier'
|
||||||
@@ -984,6 +987,7 @@ class KeyboardEvent(InputEvent):
|
|||||||
if cthulhu_state.bypassNextCommand:
|
if cthulhu_state.bypassNextCommand:
|
||||||
if not self.is_modifier_key():
|
if not self.is_modifier_key():
|
||||||
cthulhu_state.bypassNextCommand = False
|
cthulhu_state.bypassNextCommand = False
|
||||||
|
cthulhu_modifier_manager.getManager().refreshCthulhuModifiers("Bypass next command disabled")
|
||||||
self._script.addKeyGrabs()
|
self._script.addKeyGrabs()
|
||||||
return False, 'Bypass next command'
|
return False, 'Bypass next command'
|
||||||
|
|
||||||
@@ -999,34 +1003,6 @@ class KeyboardEvent(InputEvent):
|
|||||||
|
|
||||||
return False, 'Unaddressed case'
|
return False, 'Unaddressed case'
|
||||||
|
|
||||||
def _lock_mod(self):
|
|
||||||
def lock_mod(modifiers, modifier):
|
|
||||||
def lockit():
|
|
||||||
try:
|
|
||||||
if modifiers & modifier:
|
|
||||||
lock = Atspi.KeySynthType.UNLOCKMODIFIERS
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "Unlocking capslock", True)
|
|
||||||
else:
|
|
||||||
lock = Atspi.KeySynthType.LOCKMODIFIERS
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "Locking capslock", True)
|
|
||||||
Atspi.generate_keyboard_event(modifier, "", lock)
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "Done with capslock", True)
|
|
||||||
except Exception:
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "Could not trigger capslock, " \
|
|
||||||
"at-spi2-core >= 2.32 is needed for triggering capslock", True)
|
|
||||||
pass
|
|
||||||
return lockit
|
|
||||||
if self.event_string == "Caps_Lock":
|
|
||||||
modifier = 1 << Atspi.ModifierType.SHIFTLOCK
|
|
||||||
elif self.event_string == "Shift_Lock":
|
|
||||||
modifier = 1 << Atspi.ModifierType.SHIFT
|
|
||||||
else:
|
|
||||||
tokens = ["Unknown locking key", self.event_string]
|
|
||||||
debug.printTokens(debug.LEVEL_WARNING, tokens, True)
|
|
||||||
return
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "Scheduling capslock", True)
|
|
||||||
GLib.timeout_add(1, lock_mod(self.modifiers, modifier))
|
|
||||||
|
|
||||||
def _consume(self):
|
def _consume(self):
|
||||||
startTime = time.time()
|
startTime = time.time()
|
||||||
data = "'%s' (%d)" % (self.event_string, self.hw_code)
|
data = "'%s' (%d)" % (self.event_string, self.hw_code)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ cthulhu_python_sources = files([
|
|||||||
'colornames.py',
|
'colornames.py',
|
||||||
'common_keyboardmap.py',
|
'common_keyboardmap.py',
|
||||||
'cthulhuVersion.py',
|
'cthulhuVersion.py',
|
||||||
|
'cthulhu_modifier_manager.py',
|
||||||
'cthulhu_state.py',
|
'cthulhu_state.py',
|
||||||
'date_and_time_presenter.py',
|
'date_and_time_presenter.py',
|
||||||
'dbus_service.py',
|
'dbus_service.py',
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import cthulhu.input_event_manager as input_event_manager
|
|||||||
import cthulhu.keybindings as keybindings
|
import cthulhu.keybindings as keybindings
|
||||||
import cthulhu.messages as messages
|
import cthulhu.messages as messages
|
||||||
import cthulhu.cthulhu as cthulhu
|
import cthulhu.cthulhu as cthulhu
|
||||||
|
import cthulhu.cthulhu_modifier_manager as cthulhu_modifier_manager
|
||||||
import cthulhu.cthulhu_state as cthulhu_state
|
import cthulhu.cthulhu_state as cthulhu_state
|
||||||
import cthulhu.phonnames as phonnames
|
import cthulhu.phonnames as phonnames
|
||||||
import cthulhu.script as script
|
import cthulhu.script as script
|
||||||
@@ -834,6 +835,7 @@ class Script(script.Script):
|
|||||||
|
|
||||||
self.presentMessage(messages.BYPASS_MODE_ENABLED)
|
self.presentMessage(messages.BYPASS_MODE_ENABLED)
|
||||||
cthulhu_state.bypassNextCommand = True
|
cthulhu_state.bypassNextCommand = True
|
||||||
|
cthulhu_modifier_manager.getManager().unsetCthulhuModifiers("Bypass next command enabled")
|
||||||
self.removeKeyGrabs()
|
self.removeKeyGrabs()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ __license__ = "LGPL"
|
|||||||
|
|
||||||
import cthulhu.scripts.default as default
|
import cthulhu.scripts.default as default
|
||||||
import cthulhu.debug as debug
|
import cthulhu.debug as debug
|
||||||
|
import cthulhu.cthulhu_modifier_manager as cthulhu_modifier_manager
|
||||||
import cthulhu.sleep_mode_manager as sleep_mode_manager
|
import cthulhu.sleep_mode_manager as sleep_mode_manager
|
||||||
|
|
||||||
class Script(default.Script):
|
class Script(default.Script):
|
||||||
@@ -55,6 +56,7 @@ class Script(default.Script):
|
|||||||
|
|
||||||
debug.printMessage(debug.LEVEL_INFO, "SLEEP MODE SCRIPT: Activating", True)
|
debug.printMessage(debug.LEVEL_INFO, "SLEEP MODE SCRIPT: Activating", True)
|
||||||
super().activate()
|
super().activate()
|
||||||
|
cthulhu_modifier_manager.getManager().unsetCthulhuModifiers("Entering sleep mode.")
|
||||||
|
|
||||||
# Get the manager and add its bindings and handlers
|
# Get the manager and add its bindings and handlers
|
||||||
manager = sleep_mode_manager.getManager()
|
manager = sleep_mode_manager.getManager()
|
||||||
@@ -76,6 +78,7 @@ class Script(default.Script):
|
|||||||
|
|
||||||
# Restore key grabs
|
# Restore key grabs
|
||||||
self.addKeyGrabs()
|
self.addKeyGrabs()
|
||||||
|
cthulhu_modifier_manager.getManager().refreshCthulhuModifiers("Exiting sleep mode.")
|
||||||
|
|
||||||
super().deactivate()
|
super().deactivate()
|
||||||
|
|
||||||
@@ -153,4 +156,4 @@ class Script(default.Script):
|
|||||||
|
|
||||||
def get_script(app):
|
def get_script(app):
|
||||||
"""Returns the script for the given application."""
|
"""Returns the script for the given application."""
|
||||||
return Script(app)
|
return Script(app)
|
||||||
|
|||||||
Reference in New Issue
Block a user