Merge 3359ee374c into 5e4ae7261e
This commit is contained in:
commit
41d11c90e7
|
|
@ -246,7 +246,12 @@ if evdev:
|
||||||
key_events.append(evcode)
|
key_events.append(evcode)
|
||||||
devicecap = {
|
devicecap = {
|
||||||
evdev.ecodes.EV_KEY: key_events,
|
evdev.ecodes.EV_KEY: key_events,
|
||||||
evdev.ecodes.EV_REL: [evdev.ecodes.REL_WHEEL, evdev.ecodes.REL_HWHEEL],
|
evdev.ecodes.EV_REL: [
|
||||||
|
evdev.ecodes.REL_WHEEL,
|
||||||
|
evdev.ecodes.REL_HWHEEL,
|
||||||
|
evdev.ecodes.REL_WHEEL_HI_RES,
|
||||||
|
evdev.ecodes.REL_HWHEEL_HI_RES,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
# Just mock these since they won't be useful without evdev anyway
|
# Just mock these since they won't be useful without evdev anyway
|
||||||
|
|
@ -360,15 +365,23 @@ def click(button, count):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def simulate_scroll(dx, dy):
|
def simulate_scroll(dx, dy, hi_res_dx=None, hi_res_dy=None):
|
||||||
|
hi_res_dx = hi_res_dx or dx * 120
|
||||||
|
hi_res_dy = hi_res_dy or dy * 120
|
||||||
if setup_uinput():
|
if setup_uinput():
|
||||||
success = True
|
for code, delta in (
|
||||||
if dx:
|
(evdev.ecodes.REL_HWHEEL_HI_RES, hi_res_dx),
|
||||||
success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_HWHEEL, dx)
|
(evdev.ecodes.REL_WHEEL_HI_RES, hi_res_dy),
|
||||||
if dy and success:
|
(evdev.ecodes.REL_HWHEEL, dx),
|
||||||
success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_WHEEL, dy)
|
(evdev.ecodes.REL_WHEEL, dy),
|
||||||
if success:
|
):
|
||||||
return True
|
if delta:
|
||||||
|
success = simulate_uinput(evdev.ecodes.EV_REL, code, delta)
|
||||||
|
if not success:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
logger.warning("no way to simulate scrolling")
|
logger.warning("no way to simulate scrolling")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -621,8 +634,7 @@ class Process(Condition):
|
||||||
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
|
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
|
||||||
if warn:
|
if warn:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome "
|
"rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome extension - %s",
|
||||||
"extension - %s",
|
|
||||||
self,
|
self,
|
||||||
)
|
)
|
||||||
if not isinstance(process, str):
|
if not isinstance(process, str):
|
||||||
|
|
@ -1218,26 +1230,45 @@ class MouseScroll(Action):
|
||||||
amounts = amounts[0]
|
amounts = amounts[0]
|
||||||
if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])):
|
if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])):
|
||||||
if warn:
|
if warn:
|
||||||
logger.warning("rule MouseScroll argument not two numbers %s", amounts)
|
logger.warning(f"rule {self.__class__.__name__} argument not two numbers {amounts}")
|
||||||
amounts = [0, 0]
|
amounts = [0, 0]
|
||||||
self.amounts = amounts
|
self.amounts = amounts
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "MouseScroll: " + " ".join([str(a) for a in self.amounts])
|
return f"{self.__class__.__name__}: " + " ".join([str(a) for a in self.amounts])
|
||||||
|
|
||||||
def evaluate(self, feature, notification: HIDPPNotification, device, last_result):
|
def evaluate(self, feature, notification: HIDPPNotification, device, last_result):
|
||||||
amounts = self.amounts
|
amounts = self.amounts
|
||||||
if isinstance(last_result, numbers.Number):
|
if isinstance(last_result, numbers.Number):
|
||||||
amounts = [math.floor(last_result * a) for a in self.amounts]
|
amounts = [math.floor(last_result * a) for a in self.amounts]
|
||||||
if logger.isEnabledFor(logging.INFO):
|
if logger.isEnabledFor(logging.INFO):
|
||||||
logger.info("MouseScroll action: %s %s %s", self.amounts, last_result, amounts)
|
logger.info(f"{self.__class__.__name__} action: {self.amounts} {last_result} {amounts}")
|
||||||
dx, dy = amounts
|
dx, dy = amounts
|
||||||
simulate_scroll(dx, dy)
|
self._scroll(dx, dy)
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _scroll(cls, dx, dy):
|
||||||
|
simulate_scroll(dx, dy)
|
||||||
|
|
||||||
def data(self):
|
def data(self):
|
||||||
return {"MouseScroll": self.amounts[:]}
|
return {f"{self.__class__.__name__}": self.amounts[:]}
|
||||||
|
|
||||||
|
|
||||||
|
class MouseScrollHiRes(MouseScroll):
|
||||||
|
accumulated_x = 0
|
||||||
|
accumulated_y = 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _scroll(cls, hi_res_dx, hi_res_dy):
|
||||||
|
cls.accumulated_x += hi_res_dx
|
||||||
|
cls.accumulated_y += hi_res_dy
|
||||||
|
dx = cls.accumulated_x // 120
|
||||||
|
dy = cls.accumulated_y // 120
|
||||||
|
cls.accumulated_x %= 120
|
||||||
|
cls.accumulated_y %= 120
|
||||||
|
simulate_scroll(dx, dy, hi_res_dx, hi_res_dy)
|
||||||
|
|
||||||
|
|
||||||
class MouseClick(Action):
|
class MouseClick(Action):
|
||||||
|
|
@ -1405,6 +1436,7 @@ COMPONENTS = {
|
||||||
"Host": Host,
|
"Host": Host,
|
||||||
"KeyPress": KeyPress,
|
"KeyPress": KeyPress,
|
||||||
"MouseScroll": MouseScroll,
|
"MouseScroll": MouseScroll,
|
||||||
|
"MouseScrollHiRes": MouseScrollHiRes,
|
||||||
"MouseClick": MouseClick,
|
"MouseClick": MouseClick,
|
||||||
"Set": Set,
|
"Set": Set,
|
||||||
"Execute": Execute,
|
"Execute": Execute,
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,7 @@ class ActionMenu:
|
||||||
[
|
[
|
||||||
(_("Key press"), diversion.KeyPress, "space"),
|
(_("Key press"), diversion.KeyPress, "space"),
|
||||||
(_("Mouse scroll"), diversion.MouseScroll, [0, 0]),
|
(_("Mouse scroll"), diversion.MouseScroll, [0, 0]),
|
||||||
|
(_("Mouse scroll (hi-res)"), diversion.MouseScrollHiRes, [0, 0]),
|
||||||
(_("Mouse click"), diversion.MouseClick, ["left", 1]),
|
(_("Mouse click"), diversion.MouseClick, ["left", 1]),
|
||||||
(_("Set"), diversion.Set, [None, "", None]),
|
(_("Set"), diversion.Set, [None, "", None]),
|
||||||
(_("Execute"), diversion.Execute, [""]),
|
(_("Execute"), diversion.Execute, [""]),
|
||||||
|
|
@ -1865,6 +1866,7 @@ COMPONENT_UI: dict[Any, RuleComponentUI] = {
|
||||||
diversion.MouseGesture: rule_conditions.MouseGestureUI,
|
diversion.MouseGesture: rule_conditions.MouseGestureUI,
|
||||||
diversion.KeyPress: rule_actions.KeyPressUI,
|
diversion.KeyPress: rule_actions.KeyPressUI,
|
||||||
diversion.MouseScroll: rule_actions.MouseScrollUI,
|
diversion.MouseScroll: rule_actions.MouseScrollUI,
|
||||||
|
diversion.MouseScrollHiRes: rule_actions.MouseScrollHiResUI,
|
||||||
diversion.MouseClick: rule_actions.MouseClickUI,
|
diversion.MouseClick: rule_actions.MouseClickUI,
|
||||||
diversion.Execute: rule_actions.ExecuteUI,
|
diversion.Execute: rule_actions.ExecuteUI,
|
||||||
diversion.Set: SetUI,
|
diversion.Set: SetUI,
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,24 @@ class MouseScrollUI(ActionUI):
|
||||||
return f"{x}, {y}"
|
return f"{x}, {y}"
|
||||||
|
|
||||||
|
|
||||||
|
class MouseScrollHiResUI(MouseScrollUI):
|
||||||
|
CLASS = diversion.MouseScrollHiRes
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
super().create_widgets()
|
||||||
|
self.label.set_text(
|
||||||
|
_(
|
||||||
|
"Simulate a high-resolution scroll.\n"
|
||||||
|
'One detent click, or "regular" scroll unit, is represented by 120 high resolution scroll units.\n'
|
||||||
|
"Always requires write access to /dev/uinput."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def left_label(cls, component):
|
||||||
|
return _("Mouse scroll (hi-res)")
|
||||||
|
|
||||||
|
|
||||||
class MouseClickUI(ActionUI):
|
class MouseClickUI(ActionUI):
|
||||||
CLASS = diversion.MouseClick
|
CLASS = diversion.MouseClick
|
||||||
MIN_VALUE = 1
|
MIN_VALUE = 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue