Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
rloutrel authored Oct 14, 2024
2 parents 881e0f9 + 0cd9c0c commit 752b66d
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 410 deletions.
8 changes: 4 additions & 4 deletions lib/logitech_receiver/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
from . import hidpp10
from . import hidpp10_constants
from . import hidpp20
from . import hidpp20_constants
from . import settings
from . import settings_templates
from .common import Alert
from .common import Battery
from .hidpp20_constants import SupportedFeature

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -295,9 +295,9 @@ def polling_rate(self):
@property
def led_effects(self):
if not self._led_effects and self.online and self.protocol >= 2.0:
if hidpp20_constants.FEATURE.COLOR_LED_EFFECTS in self.features:
if SupportedFeature.COLOR_LED_EFFECTS in self.features:
self._led_effects = hidpp20.LEDEffectsInfo(self)
elif hidpp20_constants.FEATURE.RGB_EFFECTS in self.features:
elif SupportedFeature.RGB_EFFECTS in self.features:
self._led_effects = hidpp20.RGBEffectsInfo(self)
return self._led_effects

Expand Down Expand Up @@ -435,7 +435,7 @@ def changed(self, active=None, alert=Alert.NONE, reason=None, push=False):
was_active is None
or not was_active
or push
and (not self.features or hidpp20_constants.FEATURE.WIRELESS_DEVICE_STATUS not in self.features)
and (not self.features or SupportedFeature.WIRELESS_DEVICE_STATUS not in self.features)
):
if logger.isEnabledFor(logging.INFO):
logger.info("%s pushing device settings %s", self, self.settings)
Expand Down
138 changes: 70 additions & 68 deletions lib/logitech_receiver/diversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import evdev

from .common import NamedInt
from .hidpp20 import FEATURE
from .hidpp20 import SupportedFeature
from .special_keys import CONTROL

gi.require_version("Gdk", "3.0") # isort:skip
Expand Down Expand Up @@ -434,7 +434,7 @@ def simulate_scroll(dx, dy):

def thumb_wheel_up(f, r, d, a):
global thumb_wheel_displacement
if f != FEATURE.THUMB_WHEEL or r != 0:
if f != SupportedFeature.THUMB_WHEEL or r != 0:
return False
if a is None:
return signed(d[0:2]) < 0 and signed(d[0:2])
Expand All @@ -447,7 +447,7 @@ def thumb_wheel_up(f, r, d, a):

def thumb_wheel_down(f, r, d, a):
global thumb_wheel_displacement
if f != FEATURE.THUMB_WHEEL or r != 0:
if f != SupportedFeature.THUMB_WHEEL or r != 0:
return False
if a is None:
return signed(d[0:2]) > 0 and signed(d[0:2])
Expand All @@ -460,40 +460,40 @@ def thumb_wheel_down(f, r, d, a):

def charging(f, r, d, _a):
if (
(f == FEATURE.BATTERY_STATUS and r == 0 and 1 <= d[2] <= 4)
or (f == FEATURE.BATTERY_VOLTAGE and r == 0 and d[2] & (1 << 7))
or (f == FEATURE.UNIFIED_BATTERY and r == 0 and 1 <= d[2] <= 3)
(f == SupportedFeature.BATTERY_STATUS and r == 0 and 1 <= d[2] <= 4)
or (f == SupportedFeature.BATTERY_VOLTAGE and r == 0 and d[2] & (1 << 7))
or (f == SupportedFeature.UNIFIED_BATTERY and r == 0 and 1 <= d[2] <= 3)
):
return 1
else:
return False


TESTS = {
"crown_right": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[1] < 128 and d[1], False],
"crown_left": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[1] >= 128 and 256 - d[1], False],
"crown_right_ratchet": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[2] < 128 and d[2], False],
"crown_left_ratchet": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[2] >= 128 and 256 - d[2], False],
"crown_tap": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[5] == 0x01 and d[5], False],
"crown_start_press": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[6] == 0x01 and d[6], False],
"crown_end_press": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and d[6] == 0x05 and d[6], False],
"crown_pressed": [lambda f, r, d, a: f == FEATURE.CROWN and r == 0 and 0x01 <= d[6] <= 0x04 and d[6], False],
"crown_right": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] < 128 and d[1], False],
"crown_left": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] >= 128 and 256 - d[1], False],
"crown_right_ratchet": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] < 128 and d[2], False],
"crown_left_ratchet": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] >= 128 and 256 - d[2], False],
"crown_tap": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[5] == 0x01 and d[5], False],
"crown_start_press": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x01 and d[6], False],
"crown_end_press": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x05 and d[6], False],
"crown_pressed": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and 0x01 <= d[6] <= 0x04 and d[6], False],
"thumb_wheel_up": [thumb_wheel_up, True],
"thumb_wheel_down": [thumb_wheel_down, True],
"lowres_wheel_up": [
lambda f, r, d, a: f == FEATURE.LOWRES_WHEEL and r == 0 and signed(d[0:1]) > 0 and signed(d[0:1]),
lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) > 0 and signed(d[0:1]),
False,
],
"lowres_wheel_down": [
lambda f, r, d, a: f == FEATURE.LOWRES_WHEEL and r == 0 and signed(d[0:1]) < 0 and signed(d[0:1]),
lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) < 0 and signed(d[0:1]),
False,
],
"hires_wheel_up": [
lambda f, r, d, a: f == FEATURE.HIRES_WHEEL and r == 0 and signed(d[1:3]) > 0 and signed(d[1:3]),
lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) > 0 and signed(d[1:3]),
False,
],
"hires_wheel_down": [
lambda f, r, d, a: f == FEATURE.HIRES_WHEEL and r == 0 and signed(d[1:3]) < 0 and signed(d[1:3]),
lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) < 0 and signed(d[1:3]),
False,
],
"charging": [charging, False],
Expand Down Expand Up @@ -738,12 +738,13 @@ def data(self):


class Feature(Condition):
def __init__(self, feature, warn=True):
if not (isinstance(feature, str) and feature in FEATURE):
def __init__(self, feature: str, warn: bool = True):
try:
self.feature = SupportedFeature[feature]
except KeyError:
self.feature = None
if warn:
logger.warning("rule Feature argument not name of a feature: %s", feature)
self.feature = None
self.feature = FEATURE[feature]

def __str__(self):
return "Feature: " + str(self.feature)
Expand Down Expand Up @@ -1052,7 +1053,7 @@ def __str__(self):
def evaluate(self, feature, notification: HIDPPNotification, device, last_result):
if logger.isEnabledFor(logging.DEBUG):
logger.debug("evaluate condition: %s", self)
if feature == FEATURE.MOUSE_GESTURE:
if feature == SupportedFeature.MOUSE_GESTURE:
d = notification.data
data = struct.unpack("!" + (int(len(d) / 2) * "h"), d)
data_offset = 1
Expand Down Expand Up @@ -1478,15 +1479,15 @@ def data(self):
)


def key_is_down(key):
def key_is_down(key: NamedInt) -> bool:
"""Checks if given key is pressed or not."""
if key == CONTROL.MR:
return mr_key_down
elif CONTROL.M1 <= key <= CONTROL.M8:
return bool(m_keys_down & (0x01 << (key - CONTROL.M1)))
elif CONTROL.G1 <= key <= CONTROL.G32:
return bool(g_keys_down & (0x01 << (key - CONTROL.G1)))
else:
return key in keys_down
return key in keys_down


def evaluate_rules(feature, notification: HIDPPNotification, device):
Expand All @@ -1495,51 +1496,52 @@ def evaluate_rules(feature, notification: HIDPPNotification, device):
rules.evaluate(feature, notification, device, True)


# process a notification
def process_notification(device, notification: HIDPPNotification, feature):
def process_notification(device, notification: HIDPPNotification, feature) -> None:
"""Processes HID++ notifications."""
global keys_down, g_keys_down, m_keys_down, mr_key_down, key_down, key_up, thumb_wheel_displacement
key_down, key_up = None, None
# need to keep track of keys that are down to find a new key down
if feature == FEATURE.REPROG_CONTROLS_V4 and notification.address == 0x00:
new_keys_down = struct.unpack("!4H", notification.data[:8])
for key in new_keys_down:
if key and key not in keys_down:
key_down = key
for key in keys_down:
if key and key not in new_keys_down:
key_up = key
keys_down = new_keys_down
# and also G keys down
elif feature == FEATURE.GKEY and notification.address == 0x00:
new_g_keys_down = struct.unpack("<I", notification.data[:4])[0]
for i in range(32):
if new_g_keys_down & (0x01 << i) and not g_keys_down & (0x01 << i):
key_down = CONTROL["G" + str(i + 1)]
if g_keys_down & (0x01 << i) and not new_g_keys_down & (0x01 << i):
key_up = CONTROL["G" + str(i + 1)]
g_keys_down = new_g_keys_down
# and also M keys down
elif feature == FEATURE.MKEYS and notification.address == 0x00:
new_m_keys_down = struct.unpack("!1B", notification.data[:1])[0]
for i in range(1, 9):
if new_m_keys_down & (0x01 << (i - 1)) and not m_keys_down & (0x01 << (i - 1)):
key_down = CONTROL["M" + str(i)]
if m_keys_down & (0x01 << (i - 1)) and not new_m_keys_down & (0x01 << (i - 1)):
key_up = CONTROL["M" + str(i)]
m_keys_down = new_m_keys_down
# and also MR key
elif feature == FEATURE.MR and notification.address == 0x00:
new_mr_key_down = struct.unpack("!1B", notification.data[:1])[0]
if not mr_key_down and new_mr_key_down:
key_down = CONTROL["MR"]
if mr_key_down and not new_mr_key_down:
key_up = CONTROL["MR"]
mr_key_down = new_mr_key_down
# keep track of thumb wheel movment
elif feature == FEATURE.THUMB_WHEEL and notification.address == 0x00:
if notification.data[4] <= 0x01: # when wheel starts, zero out last movement
thumb_wheel_displacement = 0
thumb_wheel_displacement += signed(notification.data[0:2])
if notification.address == 0x00:
if feature == SupportedFeature.REPROG_CONTROLS_V4:
new_keys_down = struct.unpack("!4H", notification.data[:8])
for key in new_keys_down:
if key and key not in keys_down:
key_down = key
for key in keys_down:
if key and key not in new_keys_down:
key_up = key
keys_down = new_keys_down
# and also G keys down
elif feature == SupportedFeature.GKEY:
new_g_keys_down = struct.unpack("<I", notification.data[:4])[0]
for i in range(32):
if new_g_keys_down & (0x01 << i) and not g_keys_down & (0x01 << i):
key_down = CONTROL["G" + str(i + 1)]
if g_keys_down & (0x01 << i) and not new_g_keys_down & (0x01 << i):
key_up = CONTROL["G" + str(i + 1)]
g_keys_down = new_g_keys_down
# and also M keys down
elif feature == SupportedFeature.MKEYS:
new_m_keys_down = struct.unpack("!1B", notification.data[:1])[0]
for i in range(1, 9):
if new_m_keys_down & (0x01 << (i - 1)) and not m_keys_down & (0x01 << (i - 1)):
key_down = CONTROL["M" + str(i)]
if m_keys_down & (0x01 << (i - 1)) and not new_m_keys_down & (0x01 << (i - 1)):
key_up = CONTROL["M" + str(i)]
m_keys_down = new_m_keys_down
# and also MR key
elif feature == SupportedFeature.MR:
new_mr_key_down = struct.unpack("!1B", notification.data[:1])[0]
if not mr_key_down and new_mr_key_down:
key_down = CONTROL["MR"]
if mr_key_down and not new_mr_key_down:
key_up = CONTROL["MR"]
mr_key_down = new_mr_key_down
# keep track of thumb wheel movement
elif feature == SupportedFeature.THUMB_WHEEL:
if notification.data[4] <= 0x01: # when wheel starts, zero out last movement
thumb_wheel_displacement = 0
thumb_wheel_displacement += signed(notification.data[0:2])

GLib.idle_add(evaluate_rules, feature, notification, device)

Expand Down
Loading

0 comments on commit 752b66d

Please sign in to comment.