rules: make rule processing conditional on X11 being available

This commit is contained in:
Peter F. Patel-Schneider 2020-11-20 08:07:27 -05:00
parent 60afd53257
commit 419a7722ad
4 changed files with 59 additions and 50 deletions

View File

@ -109,7 +109,8 @@ program.
Solaar can process HID++ Feature Notifications from devices to, for example,
change the speed of some thumb wheels. For more information on this capability of Solaar see
[the rules page](https://pwr-solaar.github.io/Solaar/rules).
[the rules page](https://pwr-solaar.github.io/Solaar/rules). As much of rule processing
depends on X11, this capability is only when running under X11.
Users can edit rules using a GUI by clicking on the `Edit Rule` button in the Solaar main window.

View File

@ -3,6 +3,8 @@ title: Rule Processing of HID++ Notifications
layout: page
---
Note that rule processing is only available when running under X11.
Logitech devices that use HID++ version 2.0 or greater produce feature-based
notifications that Solaar can process using a simple rule language. For
example, using rules Solaar can emulate an `XF86_MonBrightnessDown` key tap

View File

@ -25,12 +25,7 @@ from logging import getLogger
import _thread
import psutil
import Xlib
from Xlib import X
from Xlib.display import Display
from Xlib.ext import record
from Xlib.protocol import rq
from yaml import add_representer as _yaml_add_representer
from yaml import dump_all as _yaml_dump_all
from yaml import safe_load_all as _yaml_safe_load_all
@ -42,7 +37,21 @@ from .special_keys import CONTROL as _CONTROL
_log = getLogger(__name__)
del getLogger
Xlib.XK.load_keysym_group('xf86')
# many of the rule features require X11 so turn rule processing off if X11 is not available
try:
import Xlib
from Xlib import X
from Xlib.display import Display
from Xlib.ext import record
from Xlib.protocol import rq
from Xlib import XK as _XK
_XK.load_keysym_group('xf86')
XK_KEYS = vars(_XK)
x11 = True
except Exception:
_log.warn('Xlib not available - rules will not be activated')
XK_KEYS = {}
x11 = False
# determine name of active process
@ -118,6 +127,7 @@ def key_press_handler(reply):
current_key_modifiers = event.state & ~(1 << mod) if mod is not None else event.state
if x11:
_thread.start_new_thread(display.record_enable_context, (context, key_press_handler))
# display.record_free_context(context) when should this be done??
@ -578,28 +588,23 @@ COMPONENTS = {
'Execute': Execute,
}
built_in_rules = Rule([])
if x11:
built_in_rules = Rule([
## Some malformed Rules for testing
## Rule([Process(0), Feature(0), Modifiers(['XX', 0]), Modifiers('XXX'), Modifiers([0]),
## KeyPress(['XXXXX', 0]), KeyPress(['XXXXXX']), KeyPress(0),
## MouseScroll(0), MouseScroll([0, 0, 0]), MouseScroll(['a', 0]),
## Rule(["XXXXXXX"])]),
## Rule([Feature(0)]),
## Rule([Modifiers(['XXXXXXXXX', 0])]),
## Rule([KeyPress(['XXXXXSSSSS', 0])]),
{'Rule': [ # Implement problematic keys for Craft and MX Master
{'Feature': 'REPROG_CONTROLS_V4'},
{'Report': 0x0},
{'Rule': [{'Key': 'Brightness Down'}, {'KeyPress': 'XF86_MonBrightnessDown'}]},
{'Rule': [{'Key': 'Brightness Up'}, {'KeyPress': 'XF86_MonBrightnessUp'}]},
]},
{'Rule': [ # In firefox, crown movements emits keys that move up and down if not pressed, rotate through tabs otherwise
{'Rule': [ # In firefox, crown emits keys that move up and down if not pressed, rotate through tabs otherwise
{'Process': 'firefox'},
{'Feature': 'CROWN'},
{'Report': 0x0},
{'Rule': [{'Test': 'crown_pressed'}, {'Test': 'crown_right_ratchet'}, {'KeyPress': ['Control_R', 'Tab']}]},
{'Rule': [{'Test': 'crown_pressed'}, {'Test': 'crown_left_ratchet'}, {'KeyPress': ['Control_R', 'Shift_R', 'Tab']}]},
{'Rule': [{'Test': 'crown_pressed'},
{'Test': 'crown_left_ratchet'},
{'KeyPress': ['Control_R', 'Shift_R', 'Tab']}]},
{'Rule': [{'Test': 'crown_right_ratchet'}, {'KeyPress': 'Down'}]},
Rule([Test('crown_left_ratchet'), KeyPress(['Up'])]),
]},
@ -621,6 +626,8 @@ built_in_rules = Rule([
# process a notification
def process_notification(device, status, notification, feature):
if not x11:
return
global keys_down, key_down
key_down = None
# need to keep track of keys that are down to find a new key down

View File

@ -24,10 +24,9 @@ from contextlib import contextmanager as contextlib_contextmanager
from logging import getLogger
from shlex import quote as shlex_quote
import Xlib.XK
from gi.repository import Gdk, GObject, Gtk
from logitech_receiver import diversion as _DIV
from logitech_receiver.diversion import XK_KEYS as _XK_KEYS
from logitech_receiver.diversion import buttons as _buttons
from logitech_receiver.hidpp20 import FEATURE as _ALL_FEATURES
from logitech_receiver.special_keys import CONTROL as _CONTROL
@ -1086,7 +1085,7 @@ class ActionUI(RuleComponentUI):
class KeyPressUI(ActionUI):
CLASS = _DIV.KeyPress
KEY_NAMES = [k[3:] if k.startswith('XK_') else k for k, v in vars(Xlib.XK).items() if isinstance(v, int)]
KEY_NAMES = [k[3:] if k.startswith('XK_') else k for k, v in _XK_KEYS.items() if isinstance(v, int)]
def create_widgets(self):
self.widgets = {}