Fixes on top of refactoring
This commit is contained in:
parent
ad3916e1b8
commit
5f5c7cdcce
|
@ -20,6 +20,7 @@ import binascii
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
from enum import Flag
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
@ -589,7 +590,7 @@ class FirmwareInfo:
|
||||||
extras: str | None
|
extras: str | None
|
||||||
|
|
||||||
|
|
||||||
class BatteryStatus(IntEnum):
|
class BatteryStatus(Flag):
|
||||||
DISCHARGING = 0x00
|
DISCHARGING = 0x00
|
||||||
RECHARGING = 0x01
|
RECHARGING = 0x01
|
||||||
ALMOST_FULL = 0x02
|
ALMOST_FULL = 0x02
|
||||||
|
|
|
@ -26,7 +26,6 @@ from enum import IntEnum
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ class KeyFlag(Flag):
|
||||||
"""Capabilities and desired software handling for a control.
|
"""Capabilities and desired software handling for a control.
|
||||||
|
|
||||||
Ref: https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view
|
Ref: https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view
|
||||||
We treat bytes 4 and 8 of `getCidInfo` as a single bitfield
|
We treat bytes 4 and 8 of `getCidInfo` as a single bitfield.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ANALYTICS_KEY_EVENTS = 0x400
|
ANALYTICS_KEY_EVENTS = 0x400
|
||||||
|
@ -99,9 +98,6 @@ class KeyFlag(Flag):
|
||||||
IS_FN = 0x02
|
IS_FN = 0x02
|
||||||
MSE = 0x01
|
MSE = 0x01
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name.replace("_", " ")
|
|
||||||
|
|
||||||
|
|
||||||
class MappingFlag(Flag):
|
class MappingFlag(Flag):
|
||||||
"""Flags describing the reporting method of a control.
|
"""Flags describing the reporting method of a control.
|
||||||
|
@ -228,15 +224,17 @@ class FeaturesArray(dict):
|
||||||
|
|
||||||
class ReprogrammableKey:
|
class ReprogrammableKey:
|
||||||
"""Information about a control present on a device with the `REPROG_CONTROLS` feature.
|
"""Information about a control present on a device with the `REPROG_CONTROLS` feature.
|
||||||
Ref: https://drive.google.com/file/d/0BxbRzx7vEV7eU3VfMnRuRXktZ3M/view
|
|
||||||
Read-only properties:
|
Read-only properties:
|
||||||
- index {int} -- index in the control ID table
|
- index -- index in the control ID table
|
||||||
- key {NamedInt} -- the name of this control
|
- key -- the name of this control
|
||||||
- default_task {NamedInt} -- the native function of this control
|
- default_task -- the native function of this control
|
||||||
- flags {List[str]} -- capabilities and desired software handling of the control
|
- flags -- capabilities and desired software handling of the control
|
||||||
|
|
||||||
|
Ref: https://drive.google.com/file/d/0BxbRzx7vEV7eU3VfMnRuRXktZ3M/view
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, device: Device, index: int, cid: int, task_id: int, flags):
|
def __init__(self, device: Device, index: int, cid: int, task_id: int, flags: int):
|
||||||
self._device = device
|
self._device = device
|
||||||
self.index = index
|
self.index = index
|
||||||
self._cid = cid
|
self._cid = cid
|
||||||
|
@ -302,7 +300,7 @@ class ReprogrammableKeyV4(ReprogrammableKey):
|
||||||
return NamedInt(self._mapped_to, task)
|
return NamedInt(self._mapped_to, task)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def remappable_to(self) -> common.NamedInts:
|
def remappable_to(self):
|
||||||
self._device.keys._ensure_all_keys_queried()
|
self._device.keys._ensure_all_keys_queried()
|
||||||
ret = common.UnsortedNamedInts()
|
ret = common.UnsortedNamedInts()
|
||||||
if self.group_mask: # only keys with a non-zero gmask are remappable
|
if self.group_mask: # only keys with a non-zero gmask are remappable
|
||||||
|
@ -326,17 +324,17 @@ class ReprogrammableKeyV4(ReprogrammableKey):
|
||||||
self._getCidReporting()
|
self._getCidReporting()
|
||||||
return MappingFlag(self._mapping_flags)
|
return MappingFlag(self._mapping_flags)
|
||||||
|
|
||||||
def set_diverted(self, value: bool):
|
def set_diverted(self, value: bool) -> None:
|
||||||
"""If set, the control is diverted temporarily and reports presses as HID++ events."""
|
"""If set, the control is diverted temporarily and reports presses as HID++ events."""
|
||||||
flags = {MappingFlag.DIVERTED: value}
|
flags = {MappingFlag.DIVERTED: value}
|
||||||
self._setCidReporting(flags=flags)
|
self._setCidReporting(flags=flags)
|
||||||
|
|
||||||
def set_persistently_diverted(self, value: bool):
|
def set_persistently_diverted(self, value: bool) -> None:
|
||||||
"""If set, the control is diverted permanently and reports presses as HID++ events."""
|
"""If set, the control is diverted permanently and reports presses as HID++ events."""
|
||||||
flags = {MappingFlag.PERSISTENTLY_DIVERTED: value}
|
flags = {MappingFlag.PERSISTENTLY_DIVERTED: value}
|
||||||
self._setCidReporting(flags=flags)
|
self._setCidReporting(flags=flags)
|
||||||
|
|
||||||
def set_rawXY_reporting(self, value: bool):
|
def set_rawXY_reporting(self, value: bool) -> None:
|
||||||
"""If set, the mouse temporarily reports all its raw XY events while this control is pressed as HID++ events."""
|
"""If set, the mouse temporarily reports all its raw XY events while this control is pressed as HID++ events."""
|
||||||
flags = {MappingFlag.RAW_XY_DIVERTED: value}
|
flags = {MappingFlag.RAW_XY_DIVERTED: value}
|
||||||
self._setCidReporting(flags=flags)
|
self._setCidReporting(flags=flags)
|
||||||
|
@ -390,12 +388,6 @@ class ReprogrammableKeyV4(ReprogrammableKey):
|
||||||
"""
|
"""
|
||||||
flags = flags if flags else {} # See flake8 B006
|
flags = flags if flags else {} # See flake8 B006
|
||||||
|
|
||||||
# if MappingFlag.RAW_XY_DIVERTED in flags and flags[MappingFlag.RAW_XY_DIVERTED]:
|
|
||||||
# We need diversion to report raw XY, so divert temporarily (since XY reporting is also temporary)
|
|
||||||
# flags[MappingFlag.DIVERTED] = True
|
|
||||||
# if MappingFlag.DIVERTED in flags and not flags[MappingFlag.DIVERTED]:
|
|
||||||
# flags[MappingFlag.RAW_XY_DIVERTED] = False
|
|
||||||
|
|
||||||
# The capability required to set a given reporting flag.
|
# The capability required to set a given reporting flag.
|
||||||
FLAG_TO_CAPABILITY = {
|
FLAG_TO_CAPABILITY = {
|
||||||
MappingFlag.DIVERTED: KeyFlag.DIVERTABLE,
|
MappingFlag.DIVERTED: KeyFlag.DIVERTABLE,
|
||||||
|
@ -406,20 +398,20 @@ class ReprogrammableKeyV4(ReprogrammableKey):
|
||||||
}
|
}
|
||||||
|
|
||||||
bfield = 0
|
bfield = 0
|
||||||
for f, v in flags.items():
|
for mapping_flag, activated in flags.items():
|
||||||
key_flag = FLAG_TO_CAPABILITY[f]
|
key_flag = FLAG_TO_CAPABILITY[mapping_flag]
|
||||||
if v and key_flag not in self.flags:
|
if activated and key_flag not in self.flags:
|
||||||
raise exceptions.FeatureNotSupported(
|
raise exceptions.FeatureNotSupported(
|
||||||
msg=f'Tried to set mapping flag "{f}" on control "{self.key}" '
|
msg=f'Tried to set mapping flag "{mapping_flag}" on control "{self.key}" '
|
||||||
+ f'which does not support "{key_flag}" on device {self._device}.'
|
+ f'which does not support "{key_flag}" on device {self._device}.'
|
||||||
)
|
)
|
||||||
bfield |= int(f.value) if v else 0
|
bfield |= mapping_flag.value if activated else 0
|
||||||
bfield |= int(f.value) << 1 # The 'Xvalid' bit
|
bfield |= mapping_flag.value << 1 # The 'Xvalid' bit
|
||||||
if self._mapping_flags: # update flags if already read
|
if self._mapping_flags: # update flags if already read
|
||||||
if v:
|
if activated:
|
||||||
self._mapping_flags |= int(f.value)
|
self._mapping_flags |= mapping_flag.value
|
||||||
else:
|
else:
|
||||||
self._mapping_flags &= ~int(f.value)
|
self._mapping_flags &= ~mapping_flag.value
|
||||||
|
|
||||||
if remap != 0 and remap not in self.remappable_to:
|
if remap != 0 and remap not in self.remappable_to:
|
||||||
raise exceptions.FeatureNotSupported(
|
raise exceptions.FeatureNotSupported(
|
||||||
|
@ -1169,26 +1161,29 @@ class RGBEffectsInfo(LEDEffectsInfo): # effects that the LEDs can do using RGB_
|
||||||
|
|
||||||
ButtonBehaviors = common.NamedInts(MacroExecute=0x0, MacroStop=0x1, MacroStopAll=0x2, Send=0x8, Function=0x9)
|
ButtonBehaviors = common.NamedInts(MacroExecute=0x0, MacroStop=0x1, MacroStopAll=0x2, Send=0x8, Function=0x9)
|
||||||
ButtonMappingTypes = common.NamedInts(No_Action=0x0, Button=0x1, Modifier_And_Key=0x2, Consumer_Key=0x3)
|
ButtonMappingTypes = common.NamedInts(No_Action=0x0, Button=0x1, Modifier_And_Key=0x2, Consumer_Key=0x3)
|
||||||
ButtonFunctions = common.NamedInts(
|
|
||||||
No_Action=0x0,
|
|
||||||
Tilt_Left=0x1,
|
class ButtonFunctions(IntEnum):
|
||||||
Tilt_Right=0x2,
|
NO_ACTION = 0x0
|
||||||
Next_DPI=0x3,
|
TILT_LEFT = 0x1
|
||||||
Previous_DPI=0x4,
|
TILT_RIGHT = 0x2
|
||||||
Cycle_DPI=0x5,
|
NEXT_DPI = 0x3
|
||||||
Default_DPI=0x6,
|
PREVIOUS_DPI = 0x4
|
||||||
Shift_DPI=0x7,
|
CYCLE_DPI = 0x5
|
||||||
Next_Profile=0x8,
|
DEFAULT_DPI = 0x6
|
||||||
Previous_Profile=0x9,
|
SHIFT_DPI = 0x7
|
||||||
Cycle_Profile=0xA,
|
NEXT_PROFILE = 0x8
|
||||||
G_Shift=0xB,
|
PREVIOUS_PROFILE = 0x9
|
||||||
Battery_Status=0xC,
|
CYCLE_PROFILE = 0xA
|
||||||
Profile_Select=0xD,
|
G_SHIFT = 0xB
|
||||||
Mode_Switch=0xE,
|
BATTERY_STATUS = 0xC
|
||||||
Host_Button=0xF,
|
PROFILE_SELECT = 0xD
|
||||||
Scroll_Down=0x10,
|
MODE_SWITCH = 0xE
|
||||||
Scroll_Up=0x11,
|
HOST_BUTTON = 0xF
|
||||||
)
|
SCROLL_DOWN = 0x10
|
||||||
|
SCROLL_UP = 0x11
|
||||||
|
|
||||||
|
|
||||||
ButtonButtons = special_keys.MOUSE_BUTTONS
|
ButtonButtons = special_keys.MOUSE_BUTTONS
|
||||||
ButtonModifiers = special_keys.modifiers
|
ButtonModifiers = special_keys.modifiers
|
||||||
ButtonKeys = special_keys.USB_HID_KEYCODES
|
ButtonKeys = special_keys.USB_HID_KEYCODES
|
||||||
|
@ -1213,32 +1208,37 @@ class Button:
|
||||||
return dumper.represent_mapping("!Button", data.__dict__, flow_style=True)
|
return dumper.represent_mapping("!Button", data.__dict__, flow_style=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bytes(cls, bytes):
|
def from_bytes(cls, bytes_) -> Button:
|
||||||
behavior = ButtonBehaviors[bytes[0] >> 4]
|
behavior_id = bytes_[0] >> 4
|
||||||
|
behavior = ButtonBehaviors[behavior_id]
|
||||||
if behavior == ButtonBehaviors.MacroExecute or behavior == ButtonBehaviors.MacroStop:
|
if behavior == ButtonBehaviors.MacroExecute or behavior == ButtonBehaviors.MacroStop:
|
||||||
sector = ((bytes[0] & 0x0F) << 8) + bytes[1]
|
sector = ((bytes_[0] & 0x0F) << 8) + bytes_[1]
|
||||||
address = (bytes[2] << 8) + bytes[3]
|
address = (bytes_[2] << 8) + bytes_[3]
|
||||||
result = cls(behavior=behavior, sector=sector, address=address)
|
result = cls(behavior=behavior, sector=sector, address=address)
|
||||||
elif behavior == ButtonBehaviors.Send:
|
elif behavior == ButtonBehaviors.Send:
|
||||||
mapping_type = ButtonMappingTypes[bytes[1]]
|
mapping_type = ButtonMappingTypes[bytes_[1]]
|
||||||
if mapping_type == ButtonMappingTypes.Button:
|
if mapping_type == ButtonMappingTypes.Button:
|
||||||
value = ButtonButtons[(bytes[2] << 8) + bytes[3]]
|
value = ButtonButtons[(bytes_[2] << 8) + bytes_[3]]
|
||||||
result = cls(behavior=behavior, type=mapping_type, value=value)
|
result = cls(behavior=behavior, type=mapping_type, value=value)
|
||||||
elif mapping_type == ButtonMappingTypes.Modifier_And_Key:
|
elif mapping_type == ButtonMappingTypes.Modifier_And_Key:
|
||||||
modifiers = bytes[2]
|
modifiers = bytes_[2]
|
||||||
value = ButtonKeys[bytes[3]]
|
value = ButtonKeys[bytes_[3]]
|
||||||
result = cls(behavior=behavior, type=mapping_type, modifiers=modifiers, value=value)
|
result = cls(behavior=behavior, type=mapping_type, modifiers=modifiers, value=value)
|
||||||
elif mapping_type == ButtonMappingTypes.Consumer_Key:
|
elif mapping_type == ButtonMappingTypes.Consumer_Key:
|
||||||
value = ButtonConsumerKeys[(bytes[2] << 8) + bytes[3]]
|
value = ButtonConsumerKeys[(bytes_[2] << 8) + bytes_[3]]
|
||||||
result = cls(behavior=behavior, type=mapping_type, value=value)
|
result = cls(behavior=behavior, type=mapping_type, value=value)
|
||||||
elif mapping_type == ButtonMappingTypes.No_Action:
|
elif mapping_type == ButtonMappingTypes.No_Action:
|
||||||
result = cls(behavior=behavior, type=mapping_type)
|
result = cls(behavior=behavior, type=mapping_type)
|
||||||
elif behavior == ButtonBehaviors.Function:
|
elif behavior == ButtonBehaviors.Function:
|
||||||
value = ButtonFunctions[bytes[1]] if ButtonFunctions[bytes[1]] is not None else bytes[1]
|
second_byte = bytes_[1]
|
||||||
data = bytes[3]
|
try:
|
||||||
result = cls(behavior=behavior, value=value, data=data)
|
btn_func = ButtonFunctions(second_byte).value
|
||||||
|
except ValueError:
|
||||||
|
btn_func = second_byte
|
||||||
|
data = bytes_[3]
|
||||||
|
result = cls(behavior=behavior, value=btn_func, data=data)
|
||||||
else:
|
else:
|
||||||
result = cls(behavior=bytes[0] >> 4, bytes=bytes)
|
result = cls(behavior=bytes_[0] >> 4, bytes=bytes_)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def to_bytes(self):
|
def to_bytes(self):
|
||||||
|
@ -1381,7 +1381,14 @@ class OnboardProfiles:
|
||||||
return dumper.represent_mapping("!OnboardProfiles", data.__dict__)
|
return dumper.represent_mapping("!OnboardProfiles", data.__dict__)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_profile_headers(cls, device):
|
def get_profile_headers(cls, device) -> list[tuple[int, int]]:
|
||||||
|
"""Returns profile headers.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
list[tuple[int, int]]
|
||||||
|
Tuples contain (sector, enabled).
|
||||||
|
"""
|
||||||
i = 0
|
i = 0
|
||||||
headers = []
|
headers = []
|
||||||
chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0, 0, 0, i)
|
chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0, 0, 0, i)
|
||||||
|
@ -1408,10 +1415,8 @@ class OnboardProfiles:
|
||||||
gbuttons = buttons if (shift & 0x3 == 0x2) else 0
|
gbuttons = buttons if (shift & 0x3 == 0x2) else 0
|
||||||
headers = OnboardProfiles.get_profile_headers(device)
|
headers = OnboardProfiles.get_profile_headers(device)
|
||||||
profiles = {}
|
profiles = {}
|
||||||
i = 0
|
for i, (sector, enabled) in enumerate(headers, start=1):
|
||||||
for sector, enabled in headers:
|
profiles[i] = OnboardProfile.from_dev(device, i, sector, size, enabled, buttons, gbuttons)
|
||||||
profiles[i + 1] = OnboardProfile.from_dev(device, i, sector, size, enabled, buttons, gbuttons)
|
|
||||||
i += 1
|
|
||||||
return cls(
|
return cls(
|
||||||
version=OnboardProfilesVersion,
|
version=OnboardProfilesVersion,
|
||||||
name=device.name,
|
name=device.name,
|
||||||
|
|
|
@ -23,6 +23,8 @@ import pytest
|
||||||
from logitech_receiver import common
|
from logitech_receiver import common
|
||||||
from logitech_receiver import device
|
from logitech_receiver import device
|
||||||
from logitech_receiver import hidpp20
|
from logitech_receiver import hidpp20
|
||||||
|
from logitech_receiver.common import BatteryLevelApproximation
|
||||||
|
from logitech_receiver.common import BatteryStatus
|
||||||
|
|
||||||
from . import fake_hidpp
|
from . import fake_hidpp
|
||||||
|
|
||||||
|
@ -325,14 +327,14 @@ def test_device_settings(device_info, responses, protocol, p, persister, setting
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"device_info, responses, protocol, battery, changed",
|
"device_info, responses, protocol, expected_battery, changed",
|
||||||
[
|
[
|
||||||
(di_C318, fake_hidpp.r_empty, 1.0, None, {"active": True, "alert": 0, "reason": None}),
|
(di_C318, fake_hidpp.r_empty, 1.0, None, {"active": True, "alert": 0, "reason": None}),
|
||||||
(
|
(
|
||||||
di_C318,
|
di_C318,
|
||||||
fake_hidpp.r_keyboard_1,
|
fake_hidpp.r_keyboard_1,
|
||||||
1.0,
|
1.0,
|
||||||
common.Battery(50, None, 0, None),
|
common.Battery(BatteryLevelApproximation.GOOD.value, None, BatteryStatus.DISCHARGING, None),
|
||||||
{"active": True, "alert": 0, "reason": None},
|
{"active": True, "alert": 0, "reason": None},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
@ -344,12 +346,12 @@ def test_device_settings(device_info, responses, protocol, p, persister, setting
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_device_battery(device_info, responses, protocol, battery, changed, mocker):
|
def test_device_battery(device_info, responses, protocol, expected_battery, changed, mocker):
|
||||||
test_device = FakeDevice(responses, None, None, online=True, device_info=device_info)
|
test_device = FakeDevice(responses, None, None, online=True, device_info=device_info)
|
||||||
test_device._name = "TestDevice"
|
test_device._name = "TestDevice"
|
||||||
test_device._protocol = protocol
|
test_device._protocol = protocol
|
||||||
spy_changed = mocker.spy(test_device, "changed")
|
spy_changed = mocker.spy(test_device, "changed")
|
||||||
|
|
||||||
assert test_device.battery() == battery
|
assert test_device.battery() == expected_battery
|
||||||
test_device.read_battery()
|
test_device.read_battery()
|
||||||
spy_changed.assert_called_with(**changed)
|
spy_changed.assert_called_with(**changed)
|
||||||
|
|
|
@ -23,6 +23,7 @@ from logitech_receiver import hidpp20
|
||||||
from logitech_receiver import hidpp20_constants
|
from logitech_receiver import hidpp20_constants
|
||||||
from logitech_receiver import special_keys
|
from logitech_receiver import special_keys
|
||||||
from logitech_receiver.hidpp20 import KeyFlag
|
from logitech_receiver.hidpp20 import KeyFlag
|
||||||
|
from logitech_receiver.hidpp20 import MappingFlag
|
||||||
from logitech_receiver.hidpp20_constants import GestureId
|
from logitech_receiver.hidpp20_constants import GestureId
|
||||||
|
|
||||||
from . import fake_hidpp
|
from . import fake_hidpp
|
||||||
|
@ -789,7 +790,7 @@ def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"hex, behavior, sector, address, typ, val, modifiers, data, byt",
|
"hex, expected_behavior, sector, address, typ, val, modifiers, data, byt",
|
||||||
[
|
[
|
||||||
("05010203", 0x0, 0x501, 0x0203, None, None, None, None, None),
|
("05010203", 0x0, 0x501, 0x0203, None, None, None, None, None),
|
||||||
("15020304", 0x1, 0x502, 0x0304, None, None, None, None, None),
|
("15020304", 0x1, 0x502, 0x0304, None, None, None, None, None),
|
||||||
|
@ -801,10 +802,10 @@ def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0):
|
||||||
("709090A0", 0x7, None, None, None, None, None, None, b"\x70\x90\x90\xa0"),
|
("709090A0", 0x7, None, None, None, None, None, None, b"\x70\x90\x90\xa0"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_button_bytes(hex, behavior, sector, address, typ, val, modifiers, data, byt):
|
def test_button_bytes(hex, expected_behavior, sector, address, typ, val, modifiers, data, byt):
|
||||||
button = hidpp20.Button.from_bytes(bytes.fromhex(hex))
|
button = hidpp20.Button.from_bytes(bytes.fromhex(hex))
|
||||||
|
|
||||||
assert getattr(button, "behavior", None) == behavior
|
assert getattr(button, "behavior", None) == expected_behavior
|
||||||
assert getattr(button, "sector", None) == sector
|
assert getattr(button, "sector", None) == sector
|
||||||
assert getattr(button, "address", None) == address
|
assert getattr(button, "address", None) == address
|
||||||
assert getattr(button, "type", None) == typ
|
assert getattr(button, "type", None) == typ
|
||||||
|
@ -881,7 +882,7 @@ hex3 = (
|
||||||
(hex3, "", 2, 1, 16, 0, [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF], "FFFFFFFF", "FFFFFFFFFFFFFFFFFFFFFF"),
|
(hex3, "", 2, 1, 16, 0, [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF], "FFFFFFFF", "FFFFFFFFFFFFFFFFFFFFFF"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_OnboardProfile_bytes(hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting):
|
def test_onboard_profile_bytes(hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting):
|
||||||
profile = hidpp20.OnboardProfile.from_bytes(sector, enabled, buttons, gbuttons, bytes.fromhex(hex))
|
profile = hidpp20.OnboardProfile.from_bytes(sector, enabled, buttons, gbuttons, bytes.fromhex(hex))
|
||||||
|
|
||||||
assert profile.name == name
|
assert profile.name == name
|
||||||
|
@ -902,7 +903,7 @@ def test_OnboardProfile_bytes(hex, name, sector, enabled, buttons, gbuttons, res
|
||||||
(fake_hidpp.responses_profiles_rom_2, "ONB", 1, 2, 2, 1, 254),
|
(fake_hidpp.responses_profiles_rom_2, "ONB", 1, 2, 2, 1, 254),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_OnboardProfiles_device(responses, name, count, buttons, gbuttons, sectors, size):
|
def test_onboard_profiles_device(responses, name, count, buttons, gbuttons, sectors, size):
|
||||||
device = fake_hidpp.Device(
|
device = fake_hidpp.Device(
|
||||||
name, True, 4.5, responses=responses, feature=hidpp20_constants.SupportedFeature.ONBOARD_PROFILES, offset=0x9
|
name, True, 4.5, responses=responses, feature=hidpp20_constants.SupportedFeature.ONBOARD_PROFILES, offset=0x9
|
||||||
)
|
)
|
||||||
|
@ -919,4 +920,5 @@ def test_OnboardProfiles_device(responses, name, count, buttons, gbuttons, secto
|
||||||
assert profiles.size == size
|
assert profiles.size == size
|
||||||
assert len(profiles.profiles) == count
|
assert len(profiles.profiles) == count
|
||||||
|
|
||||||
assert yaml.safe_load(yaml.dump(profiles)).to_bytes().hex() == profiles.to_bytes().hex()
|
yml_dump = yaml.dump(profiles)
|
||||||
|
assert yaml.safe_load(yml_dump).to_bytes().hex() == profiles.to_bytes().hex()
|
||||||
|
|
|
@ -108,7 +108,7 @@ def test_get_battery_voltage():
|
||||||
|
|
||||||
assert feature == SupportedFeature.BATTERY_VOLTAGE
|
assert feature == SupportedFeature.BATTERY_VOLTAGE
|
||||||
assert battery.level == 90
|
assert battery.level == 90
|
||||||
assert battery.status == common.BatteryStatus.RECHARGING
|
assert common.BatteryStatus.RECHARGING in battery.status
|
||||||
assert battery.voltage == 0x1000
|
assert battery.voltage == 0x1000
|
||||||
|
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ def test_decipher_battery_voltage():
|
||||||
|
|
||||||
assert feature == SupportedFeature.BATTERY_VOLTAGE
|
assert feature == SupportedFeature.BATTERY_VOLTAGE
|
||||||
assert battery.level == 90
|
assert battery.level == 90
|
||||||
assert battery.status == common.BatteryStatus.RECHARGING
|
assert common.BatteryStatus.RECHARGING in battery.status
|
||||||
assert battery.voltage == 0x1000
|
assert battery.voltage == 0x1000
|
||||||
|
|
||||||
|
|
||||||
|
@ -438,3 +438,14 @@ def test_feature_flag_names(code, expected_flags):
|
||||||
flags = common.flag_names(hidpp20_constants.FeatureFlag, code)
|
flags = common.flag_names(hidpp20_constants.FeatureFlag, code)
|
||||||
|
|
||||||
assert list(flags) == expected_flags
|
assert list(flags) == expected_flags
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"code, expected_name",
|
||||||
|
[
|
||||||
|
(0x00, "Unknown Location"),
|
||||||
|
(0x03, "Left Side"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_led_zone_locations(code, expected_name):
|
||||||
|
assert hidpp20.LEDZoneLocations[code] == expected_name
|
||||||
|
|
Loading…
Reference in New Issue