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. 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. 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", A `KeyPress` action takes either the name of an X11 key symbol, such as "a",
and simulates a chorded keypress on the keyboard to produce these symbols. 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, Use separate `KeyPress` actions for multiple characters,
i.e., don't use a single `KeyPress` like 'a+b'. 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", 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, then Solaar will add keypresses to produce that keysymbol,
e.g., simulating a left shift keypress to get "A" instead of "a". 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): class KeyPress(Action):
def __init__(self, keys): CLICK, DEPRESS, RELEASE = 'click', 'depress', 'release'
if isinstance(keys, str):
keys = [keys] def __init__(self, args):
self.key_names = keys self.key_names, self.action = self.regularize_args(args)
self.key_symbols = [XK_KEYS.get(k, None) for k in keys] if not isinstance(self.key_names, list):
if not all(self.key_symbols): _log.warn('rule KeyPress keys not key names %s', self.keys_names)
_log.warn('rule KeyPress not sequence of key names %s', keys)
self.key_symbols = [] 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. # 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 def keysym_to_keycode(self, keysym, modifiers): # maybe should take shift into account
@ -849,7 +863,7 @@ class KeyPress(Action):
return (keycode, level) return (keycode, level)
def __str__(self): def __str__(self):
return 'KeyPress: ' + ' '.join(self.key_names) return 'KeyPress: ' + ' '.join(self.key_names) + ' ' + self.action
def needed(self, k, modifiers): def needed(self, k, modifiers):
code = modifier_code(k) code = modifier_code(k)
@ -885,16 +899,18 @@ class KeyPress(Action):
if gkeymap: if gkeymap:
current = gkeymap.get_modifier_state() current = gkeymap.get_modifier_state()
if _log.isEnabledFor(_INFO): 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)
self.keyDown(self.key_symbols, current) if self.action != self.RELEASE:
self.keyUp(reversed(self.key_symbols), current) self.keyDown(self.key_symbols, current)
if self.action != self.DEPRESS:
self.keyUp(reversed(self.key_symbols), current)
_time.sleep(0.01) _time.sleep(0.01)
else: else:
_log.warn('no keymap so cannot determine which keycode to send') _log.warn('no keymap so cannot determine which keycode to send')
return None return None
def data(self): 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 # KeyDown is dangerous as the key can auto-repeat and make your system unusable