rules: add depress and release options to KeyPress rule action

This commit is contained in:
Peter F. Patel-Schneider 2022-06-09 08:57:56 -04:00
parent cc0ddb8df5
commit c8ba397e0e
2 changed files with 40 additions and 14 deletions

View File

@ -160,10 +160,20 @@ For settings that use gestures as an argument the internal name of the gesture i
which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.
For boolean settings '~' can be used to toggle the setting.
A `KeyPress` action takes a sequence of X11 key symbols, such as "a" or "Control+a",
and simulates a chorded keypress on the keyboard to produce these symbols.
A `KeyPress` action takes either the name of an X11 key symbol, such as "a",
a list of X11 key symbols, such as "a" or "Control+a",
or a two-element list with the first element as above
and the second element one of 'click', 'depress', or 'release'
and executes key actions on a simulated keyboard to produce these symbols.
Use separate `KeyPress` actions for multiple characters,
i.e., don't use a single `KeyPress` like 'a+b'.
The `KeyPress` action normally both depresses and releases (clicks) the keys,
but can also just depress the keys or just release the keys.
Use the depress or release options with extreme care,
ensuring that the depressed keys are later released.
Otherwise it may become difficult to use your system.
The keys are depressed in forward order and released in reverse order.
If a key symbol can only be produced by a shfited or level 3 keypress, e.g., "A",
then Solaar will add keypresses to produce that keysymbol,
e.g., simulating a left shift keypress to get "A" instead of "a".

View File

@ -820,14 +820,28 @@ class Action(RuleComponent):
class KeyPress(Action):
def __init__(self, keys):
if isinstance(keys, str):
keys = [keys]
self.key_names = keys
self.key_symbols = [XK_KEYS.get(k, None) for k in keys]
if not all(self.key_symbols):
_log.warn('rule KeyPress not sequence of key names %s', keys)
CLICK, DEPRESS, RELEASE = 'click', 'depress', 'release'
def __init__(self, args):
self.key_names, self.action = self.regularize_args(args)
if not isinstance(self.key_names, list):
_log.warn('rule KeyPress keys not key names %s', self.keys_names)
self.key_symbols = []
else:
self.key_symbols = [XK_KEYS.get(k, None) for k in self.key_names]
if not all(self.key_symbols):
_log.warn('rule KeyPress keys not key names %s', self.key_names)
self.key_symbols = []
def regularize_args(self, args):
action = self.CLICK
if not isinstance(args, list):
args = [args]
keys = args
if len(args) == 2 and args[1] in [self.CLICK, self.DEPRESS, self.RELEASE]:
keys = [args[0]] if isinstance(args[0], str) else args[0]
action = args[1]
return keys, action
# WARNING: This is an attempt to reverse the keycode to keysym mappping in XKB. It may not be completely general.
def keysym_to_keycode(self, keysym, modifiers): # maybe should take shift into account
@ -849,7 +863,7 @@ class KeyPress(Action):
return (keycode, level)
def __str__(self):
return 'KeyPress: ' + ' '.join(self.key_names)
return 'KeyPress: ' + ' '.join(self.key_names) + ' ' + self.action
def needed(self, k, modifiers):
code = modifier_code(k)
@ -885,8 +899,10 @@ class KeyPress(Action):
if gkeymap:
current = gkeymap.get_modifier_state()
if _log.isEnabledFor(_INFO):
_log.info('KeyPress action: %s, group %s, modifiers %s', self.key_names, kbdgroup(), current)
_log.info('KeyPress action: %s %s, group %s, modifiers %s', self.key_names, self.action, kbdgroup(), current)
if self.action != self.RELEASE:
self.keyDown(self.key_symbols, current)
if self.action != self.DEPRESS:
self.keyUp(reversed(self.key_symbols), current)
_time.sleep(0.01)
else:
@ -894,7 +910,7 @@ class KeyPress(Action):
return None
def data(self):
return {'KeyPress': [str(k) for k in self.key_names]}
return {'KeyPress': [[str(k) for k in self.key_names], self.action]}
# KeyDown is dangerous as the key can auto-repeat and make your system unusable