logitech_receiver: Move hidpp20 constants into new module

Related #1097
This commit is contained in:
Matthias Hagmann 2024-02-14 20:41:49 +01:00 committed by Peter F. Patel-Schneider
parent 2fcab65486
commit 5f487dd3b2
8 changed files with 296 additions and 280 deletions

View File

@ -23,8 +23,8 @@ from .common import FirmwareInfo as _FirmwareInfo
from .common import bytes2int as _bytes2int
from .common import int2bytes as _int2bytes
from .common import strhex as _strhex
from .hidpp20 import BATTERY_STATUS, FIRMWARE_KIND
from .hidpp10_constants import REGISTERS
from .hidpp20_constants import BATTERY_STATUS, FIRMWARE_KIND
logger = logging.getLogger(__name__)

View File

@ -37,6 +37,8 @@ from .common import UnsortedNamedInts as _UnsortedNamedInts
from .common import bytes2int as _bytes2int
from .common import crc16 as _crc16
from .common import int2bytes as _int2bytes
from .hidpp20_constants import (BATTERY_STATUS, CHARGE_LEVEL, CHARGE_STATUS, CHARGE_TYPE, DEVICE_KIND, ERROR, FEATURE,
FIRMWARE_KIND, GESTURE)
from .i18n import _
logger = logging.getLogger(__name__)
@ -52,180 +54,6 @@ _yaml.add_representer(int, hexint_presenter)
#
#
# <FeaturesSupported.xml sed '/LD_FID_/{s/.*LD_FID_/\t/;s/"[ \t]*Id="/=/;s/" \/>/,/p}' | sort -t= -k2
# additional features names taken from https://github.com/cvuchener/hidpp and
# https://github.com/Logitech/cpg-docs/tree/master/hidpp20
"""Possible features available on a Logitech device.
A particular device might not support all these features, and may support other
unknown features as well.
"""
FEATURE = _NamedInts(
ROOT=0x0000,
FEATURE_SET=0x0001,
FEATURE_INFO=0x0002,
# Common
DEVICE_FW_VERSION=0x0003,
DEVICE_UNIT_ID=0x0004,
DEVICE_NAME=0x0005,
DEVICE_GROUPS=0x0006,
DEVICE_FRIENDLY_NAME=0x0007,
KEEP_ALIVE=0x0008,
CONFIG_CHANGE=0x0020,
CRYPTO_ID=0x0021,
TARGET_SOFTWARE=0x0030,
WIRELESS_SIGNAL_STRENGTH=0x0080,
DFUCONTROL_LEGACY=0x00C0,
DFUCONTROL_UNSIGNED=0x00C1,
DFUCONTROL_SIGNED=0x00C2,
DFUCONTROL=0x00C3,
DFU=0x00D0,
BATTERY_STATUS=0x1000,
BATTERY_VOLTAGE=0x1001,
UNIFIED_BATTERY=0x1004,
CHARGING_CONTROL=0x1010,
LED_CONTROL=0x1300,
FORCE_PAIRING=0x1500,
GENERIC_TEST=0x1800,
DEVICE_RESET=0x1802,
OOBSTATE=0x1805,
CONFIG_DEVICE_PROPS=0x1806,
CHANGE_HOST=0x1814,
HOSTS_INFO=0x1815,
BACKLIGHT=0x1981,
BACKLIGHT2=0x1982,
BACKLIGHT3=0x1983,
ILLUMINATION=0x1990,
PRESENTER_CONTROL=0x1A00,
SENSOR_3D=0x1A01,
REPROG_CONTROLS=0x1B00,
REPROG_CONTROLS_V2=0x1B01,
REPROG_CONTROLS_V2_2=0x1B02, # LogiOptions 2.10.73 features.xml
REPROG_CONTROLS_V3=0x1B03,
REPROG_CONTROLS_V4=0x1B04,
REPORT_HID_USAGE=0x1BC0,
PERSISTENT_REMAPPABLE_ACTION=0x1C00,
WIRELESS_DEVICE_STATUS=0x1D4B,
REMAINING_PAIRING=0x1DF0,
FIRMWARE_PROPERTIES=0x1F1F,
ADC_MEASUREMENT=0x1F20,
# Mouse
LEFT_RIGHT_SWAP=0x2001,
SWAP_BUTTON_CANCEL=0x2005,
POINTER_AXIS_ORIENTATION=0x2006,
VERTICAL_SCROLLING=0x2100,
SMART_SHIFT=0x2110,
SMART_SHIFT_ENHANCED=0x2111,
HI_RES_SCROLLING=0x2120,
HIRES_WHEEL=0x2121,
LOWRES_WHEEL=0x2130,
THUMB_WHEEL=0x2150,
MOUSE_POINTER=0x2200,
ADJUSTABLE_DPI=0x2201,
EXTENDED_ADJUSTABLE_DPI=0x2202,
POINTER_SPEED=0x2205,
ANGLE_SNAPPING=0x2230,
SURFACE_TUNING=0x2240,
XY_STATS=0x2250,
WHEEL_STATS=0x2251,
HYBRID_TRACKING=0x2400,
# Keyboard
FN_INVERSION=0x40A0,
NEW_FN_INVERSION=0x40A2,
K375S_FN_INVERSION=0x40A3,
ENCRYPTION=0x4100,
LOCK_KEY_STATE=0x4220,
SOLAR_DASHBOARD=0x4301,
KEYBOARD_LAYOUT=0x4520,
KEYBOARD_DISABLE_KEYS=0x4521,
KEYBOARD_DISABLE_BY_USAGE=0x4522,
DUALPLATFORM=0x4530,
MULTIPLATFORM=0x4531,
KEYBOARD_LAYOUT_2=0x4540,
CROWN=0x4600,
# Touchpad
TOUCHPAD_FW_ITEMS=0x6010,
TOUCHPAD_SW_ITEMS=0x6011,
TOUCHPAD_WIN8_FW_ITEMS=0x6012,
TAP_ENABLE=0x6020,
TAP_ENABLE_EXTENDED=0x6021,
CURSOR_BALLISTIC=0x6030,
TOUCHPAD_RESOLUTION=0x6040,
TOUCHPAD_RAW_XY=0x6100,
TOUCHMOUSE_RAW_POINTS=0x6110,
TOUCHMOUSE_6120=0x6120,
GESTURE=0x6500,
GESTURE_2=0x6501,
# Gaming Devices
GKEY=0x8010,
MKEYS=0x8020,
MR=0x8030,
BRIGHTNESS_CONTROL=0x8040,
REPORT_RATE=0x8060,
EXTENDED_ADJUSTABLE_REPORT_RATE=0x8061,
COLOR_LED_EFFECTS=0x8070,
RGB_EFFECTS=0x8071,
PER_KEY_LIGHTING=0x8080,
PER_KEY_LIGHTING_V2=0x8081,
MODE_STATUS=0x8090,
ONBOARD_PROFILES=0x8100,
MOUSE_BUTTON_SPY=0x8110,
LATENCY_MONITORING=0x8111,
GAMING_ATTACHMENTS=0x8120,
FORCE_FEEDBACK=0x8123,
# Headsets
SIDETONE=0x8300,
EQUALIZER=0x8310,
HEADSET_OUT=0x8320,
# Fake features for Solaar internal use
MOUSE_GESTURE=0xFE00,
)
FEATURE._fallback = lambda x: 'unknown:%04X' % x
FEATURE_FLAG = _NamedInts(internal=0x20, hidden=0x40, obsolete=0x80)
DEVICE_KIND = _NamedInts(
keyboard=0x00, remote_control=0x01, numpad=0x02, mouse=0x03, touchpad=0x04, trackball=0x05, presenter=0x06, receiver=0x07
)
FIRMWARE_KIND = _NamedInts(Firmware=0x00, Bootloader=0x01, Hardware=0x02, Other=0x03)
BATTERY_OK = lambda status: status not in (BATTERY_STATUS.invalid_battery, BATTERY_STATUS.thermal_error)
BATTERY_STATUS = _NamedInts(
discharging=0x00,
recharging=0x01,
almost_full=0x02,
full=0x03,
slow_recharge=0x04,
invalid_battery=0x05,
thermal_error=0x06
)
ONBOARD_MODES = _NamedInts(MODE_NO_CHANGE=0x00, MODE_ONBOARD=0x01, MODE_HOST=0x02)
CHARGE_STATUS = _NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07)
CHARGE_LEVEL = _NamedInts(average=50, full=90, critical=5)
CHARGE_TYPE = _NamedInts(standard=0x00, fast=0x01, slow=0x02)
ERROR = _NamedInts(
unknown=0x01,
invalid_argument=0x02,
out_of_range=0x03,
hardware_error=0x04,
logitech_internal=0x05,
invalid_feature_index=0x06,
invalid_function=0x07,
busy=0x08,
unsupported=0x09
)
#
#
#
class FeaturesArray(dict):
@ -746,71 +574,6 @@ class KeysArrayPersistent(KeysArray):
logger.warn(f"Key with index {index} was expected to exist but device doesn't report it.")
# Gesture Ids for feature GESTURE_2
GESTURE = _NamedInts(
Tap1Finger=1, # task Left_Click
Tap2Finger=2, # task Right_Click
Tap3Finger=3,
Click1Finger=4, # task Left_Click
Click2Finger=5, # task Right_Click
Click3Finger=6,
DoubleTap1Finger=10,
DoubleTap2Finger=11,
DoubleTap3Finger=12,
Track1Finger=20, # action MovePointer
TrackingAcceleration=21,
TapDrag1Finger=30, # action Drag
TapDrag2Finger=31, # action SecondaryDrag
Drag3Finger=32,
TapGestures=33, # group all tap gestures under a single UI setting
FnClickGestureSuppression=34, # suppresses Tap and Edge gestures, toggled by Fn+Click
Scroll1Finger=40, # action ScrollOrPageXY / ScrollHorizontal
Scroll2Finger=41, # action ScrollOrPageXY / ScrollHorizontal
Scroll2FingerHoriz=42, # action ScrollHorizontal
Scroll2FingerVert=43, # action WheelScrolling
Scroll2FingerStateless=44,
NaturalScrolling=45, # affects native HID wheel reporting by gestures, not when diverted
Thumbwheel=46, # action WheelScrolling
VScrollInertia=48,
VScrollBallistics=49,
Swipe2FingerHoriz=50, # action PageScreen
Swipe3FingerHoriz=51, # action PageScreen
Swipe4FingerHoriz=52, # action PageScreen
Swipe3FingerVert=53,
Swipe4FingerVert=54,
LeftEdgeSwipe1Finger=60,
RightEdgeSwipe1Finger=61,
BottomEdgeSwipe1Finger=62,
TopEdgeSwipe1Finger=63,
LeftEdgeSwipe1Finger2=64, # task HorzScrollNoRepeatSet
RightEdgeSwipe1Finger2=65, # task 122 ??
BottomEdgeSwipe1Finger2=66, #
TopEdgeSwipe1Finger2=67, # task 121 ??
LeftEdgeSwipe2Finger=70,
RightEdgeSwipe2Finger=71,
BottomEdgeSwipe2Finger=72,
TopEdgeSwipe2Finger=73,
Zoom2Finger=80, # action Zoom
Zoom2FingerPinch=81, # ZoomBtnInSet
Zoom2FingerSpread=82, # ZoomBtnOutSet
Zoom3Finger=83,
Zoom2FingerStateless=84, # action Zoom
TwoFingersPresent=85,
Rotate2Finger=87,
Finger1=90,
Finger2=91,
Finger3=92,
Finger4=93,
Finger5=94,
Finger6=95,
Finger7=96,
Finger8=97,
Finger9=98,
Finger10=99,
DeviceSpecificRawData=100,
)
GESTURE._fallback = lambda x: 'unknown:%04X' % x
# Param Ids for feature GESTURE_2
PARAM = _NamedInts(
ExtraCapabilities=1, # not suitable for use
@ -912,9 +675,11 @@ class Gesture:
else:
return (None, None)
enable_offset_mask = lambda gesture: gesture._offset_mask(gesture.index)
def enable_offset_mask(gesture):
return gesture._offset_mask(gesture.index)
diversion_offset_mask = lambda gesture: gesture._offset_mask(gesture.diversion_index)
def diversion_offset_mask(gesture):
return gesture._offset_mask(gesture.diversion_index)
def enabled(self): # is the gesture enabled?
if self._enabled is None and self.index is not None:

View File

@ -0,0 +1,248 @@
from .common import NamedInts
# <FeaturesSupported.xml sed '/LD_FID_/{s/.*LD_FID_/\t/;s/"[ \t]*Id="/=/;s/" \/>/,/p}' | sort -t= -k2
# additional features names taken from https://github.com/cvuchener/hidpp and
# https://github.com/Logitech/cpg-docs/tree/master/hidpp20
"""Possible features available on a Logitech device.
A particular device might not support all these features, and may support other
unknown features as well.
"""
FEATURE = NamedInts(
ROOT=0x0000,
FEATURE_SET=0x0001,
FEATURE_INFO=0x0002,
# Common
DEVICE_FW_VERSION=0x0003,
DEVICE_UNIT_ID=0x0004,
DEVICE_NAME=0x0005,
DEVICE_GROUPS=0x0006,
DEVICE_FRIENDLY_NAME=0x0007,
KEEP_ALIVE=0x0008,
CONFIG_CHANGE=0x0020,
CRYPTO_ID=0x0021,
TARGET_SOFTWARE=0x0030,
WIRELESS_SIGNAL_STRENGTH=0x0080,
DFUCONTROL_LEGACY=0x00C0,
DFUCONTROL_UNSIGNED=0x00C1,
DFUCONTROL_SIGNED=0x00C2,
DFUCONTROL=0x00C3,
DFU=0x00D0,
BATTERY_STATUS=0x1000,
BATTERY_VOLTAGE=0x1001,
UNIFIED_BATTERY=0x1004,
CHARGING_CONTROL=0x1010,
LED_CONTROL=0x1300,
FORCE_PAIRING=0x1500,
GENERIC_TEST=0x1800,
DEVICE_RESET=0x1802,
OOBSTATE=0x1805,
CONFIG_DEVICE_PROPS=0x1806,
CHANGE_HOST=0x1814,
HOSTS_INFO=0x1815,
BACKLIGHT=0x1981,
BACKLIGHT2=0x1982,
BACKLIGHT3=0x1983,
ILLUMINATION=0x1990,
PRESENTER_CONTROL=0x1A00,
SENSOR_3D=0x1A01,
REPROG_CONTROLS=0x1B00,
REPROG_CONTROLS_V2=0x1B01,
REPROG_CONTROLS_V2_2=0x1B02, # LogiOptions 2.10.73 features.xml
REPROG_CONTROLS_V3=0x1B03,
REPROG_CONTROLS_V4=0x1B04,
REPORT_HID_USAGE=0x1BC0,
PERSISTENT_REMAPPABLE_ACTION=0x1C00,
WIRELESS_DEVICE_STATUS=0x1D4B,
REMAINING_PAIRING=0x1DF0,
FIRMWARE_PROPERTIES=0x1F1F,
ADC_MEASUREMENT=0x1F20,
# Mouse
LEFT_RIGHT_SWAP=0x2001,
SWAP_BUTTON_CANCEL=0x2005,
POINTER_AXIS_ORIENTATION=0x2006,
VERTICAL_SCROLLING=0x2100,
SMART_SHIFT=0x2110,
SMART_SHIFT_ENHANCED=0x2111,
HI_RES_SCROLLING=0x2120,
HIRES_WHEEL=0x2121,
LOWRES_WHEEL=0x2130,
THUMB_WHEEL=0x2150,
MOUSE_POINTER=0x2200,
ADJUSTABLE_DPI=0x2201,
EXTENDED_ADJUSTABLE_DPI=0x2202,
POINTER_SPEED=0x2205,
ANGLE_SNAPPING=0x2230,
SURFACE_TUNING=0x2240,
XY_STATS=0x2250,
WHEEL_STATS=0x2251,
HYBRID_TRACKING=0x2400,
# Keyboard
FN_INVERSION=0x40A0,
NEW_FN_INVERSION=0x40A2,
K375S_FN_INVERSION=0x40A3,
ENCRYPTION=0x4100,
LOCK_KEY_STATE=0x4220,
SOLAR_DASHBOARD=0x4301,
KEYBOARD_LAYOUT=0x4520,
KEYBOARD_DISABLE_KEYS=0x4521,
KEYBOARD_DISABLE_BY_USAGE=0x4522,
DUALPLATFORM=0x4530,
MULTIPLATFORM=0x4531,
KEYBOARD_LAYOUT_2=0x4540,
CROWN=0x4600,
# Touchpad
TOUCHPAD_FW_ITEMS=0x6010,
TOUCHPAD_SW_ITEMS=0x6011,
TOUCHPAD_WIN8_FW_ITEMS=0x6012,
TAP_ENABLE=0x6020,
TAP_ENABLE_EXTENDED=0x6021,
CURSOR_BALLISTIC=0x6030,
TOUCHPAD_RESOLUTION=0x6040,
TOUCHPAD_RAW_XY=0x6100,
TOUCHMOUSE_RAW_POINTS=0x6110,
TOUCHMOUSE_6120=0x6120,
GESTURE=0x6500,
GESTURE_2=0x6501,
# Gaming Devices
GKEY=0x8010,
MKEYS=0x8020,
MR=0x8030,
BRIGHTNESS_CONTROL=0x8040,
REPORT_RATE=0x8060,
EXTENDED_ADJUSTABLE_REPORT_RATE=0x8061,
COLOR_LED_EFFECTS=0x8070,
RGB_EFFECTS=0x8071,
PER_KEY_LIGHTING=0x8080,
PER_KEY_LIGHTING_V2=0x8081,
MODE_STATUS=0x8090,
ONBOARD_PROFILES=0x8100,
MOUSE_BUTTON_SPY=0x8110,
LATENCY_MONITORING=0x8111,
GAMING_ATTACHMENTS=0x8120,
FORCE_FEEDBACK=0x8123,
# Headsets
SIDETONE=0x8300,
EQUALIZER=0x8310,
HEADSET_OUT=0x8320,
# Fake features for Solaar internal use
MOUSE_GESTURE=0xFE00,
)
FEATURE._fallback = lambda x: 'unknown:%04X' % x
FEATURE_FLAG = NamedInts(internal=0x20, hidden=0x40, obsolete=0x80)
DEVICE_KIND = NamedInts(
keyboard=0x00, remote_control=0x01, numpad=0x02, mouse=0x03, touchpad=0x04, trackball=0x05, presenter=0x06, receiver=0x07
)
FIRMWARE_KIND = NamedInts(Firmware=0x00, Bootloader=0x01, Hardware=0x02, Other=0x03)
def BATTERY_OK(status):
return status not in (BATTERY_STATUS.invalid_battery, BATTERY_STATUS.thermal_error)
BATTERY_STATUS = NamedInts(
discharging=0x00,
recharging=0x01,
almost_full=0x02,
full=0x03,
slow_recharge=0x04,
invalid_battery=0x05,
thermal_error=0x06
)
ONBOARD_MODES = NamedInts(MODE_NO_CHANGE=0x00, MODE_ONBOARD=0x01, MODE_HOST=0x02)
CHARGE_STATUS = NamedInts(charging=0x00, full=0x01, not_charging=0x02, error=0x07)
CHARGE_LEVEL = NamedInts(average=50, full=90, critical=5)
CHARGE_TYPE = NamedInts(standard=0x00, fast=0x01, slow=0x02)
ERROR = NamedInts(
unknown=0x01,
invalid_argument=0x02,
out_of_range=0x03,
hardware_error=0x04,
logitech_internal=0x05,
invalid_feature_index=0x06,
invalid_function=0x07,
busy=0x08,
unsupported=0x09
)
# Gesture Ids for feature GESTURE_2
GESTURE = NamedInts(
Tap1Finger=1, # task Left_Click
Tap2Finger=2, # task Right_Click
Tap3Finger=3,
Click1Finger=4, # task Left_Click
Click2Finger=5, # task Right_Click
Click3Finger=6,
DoubleTap1Finger=10,
DoubleTap2Finger=11,
DoubleTap3Finger=12,
Track1Finger=20, # action MovePointer
TrackingAcceleration=21,
TapDrag1Finger=30, # action Drag
TapDrag2Finger=31, # action SecondaryDrag
Drag3Finger=32,
TapGestures=33, # group all tap gestures under a single UI setting
FnClickGestureSuppression=34, # suppresses Tap and Edge gestures, toggled by Fn+Click
Scroll1Finger=40, # action ScrollOrPageXY / ScrollHorizontal
Scroll2Finger=41, # action ScrollOrPageXY / ScrollHorizontal
Scroll2FingerHoriz=42, # action ScrollHorizontal
Scroll2FingerVert=43, # action WheelScrolling
Scroll2FingerStateless=44,
NaturalScrolling=45, # affects native HID wheel reporting by gestures, not when diverted
Thumbwheel=46, # action WheelScrolling
VScrollInertia=48,
VScrollBallistics=49,
Swipe2FingerHoriz=50, # action PageScreen
Swipe3FingerHoriz=51, # action PageScreen
Swipe4FingerHoriz=52, # action PageScreen
Swipe3FingerVert=53,
Swipe4FingerVert=54,
LeftEdgeSwipe1Finger=60,
RightEdgeSwipe1Finger=61,
BottomEdgeSwipe1Finger=62,
TopEdgeSwipe1Finger=63,
LeftEdgeSwipe1Finger2=64, # task HorzScrollNoRepeatSet
RightEdgeSwipe1Finger2=65, # task 122 ??
BottomEdgeSwipe1Finger2=66, #
TopEdgeSwipe1Finger2=67, # task 121 ??
LeftEdgeSwipe2Finger=70,
RightEdgeSwipe2Finger=71,
BottomEdgeSwipe2Finger=72,
TopEdgeSwipe2Finger=73,
Zoom2Finger=80, # action Zoom
Zoom2FingerPinch=81, # ZoomBtnInSet
Zoom2FingerSpread=82, # ZoomBtnOutSet
Zoom3Finger=83,
Zoom2FingerStateless=84, # action Zoom
TwoFingersPresent=85,
Rotate2Finger=87,
Finger1=90,
Finger2=91,
Finger3=92,
Finger4=93,
Finger5=94,
Finger6=95,
Finger7=96,
Finger8=97,
Finger9=98,
Finger10=99,
DeviceSpecificRawData=100,
)
GESTURE._fallback = lambda x: 'unknown:%04X' % x
# Param Ids for feature GESTURE_2
PARAM = NamedInts(
ExtraCapabilities=1, # not suitable for use
PixelZone=2, # 4 2-byte integers, left, bottom, width, height; pixels
RatioZone=3, # 4 bytes, left, bottom, width, height; unit 1/240 pad size
ScaleFactor=4, # 2-byte integer, with 256 as normal scale
)
PARAM._fallback = lambda x: 'unknown:%04X' % x

View File

@ -27,6 +27,7 @@ from solaar.ui.config_panel import record_setting
from . import diversion as _diversion
from . import hidpp10 as _hidpp10
from . import hidpp20 as _hidpp20
from . import hidpp20_constants as _hidpp20_constants
from . import settings_templates as _st
from .base import DJ_MESSAGE_ID as _DJ_MESSAGE_ID
from .common import strhex as _strhex
@ -37,7 +38,7 @@ from .status import KEYS as _K
logger = logging.getLogger(__name__)
_R = _hidpp10.REGISTERS
_F = _hidpp20.FEATURE
_F = _hidpp20_constants.FEATURE
#
#
@ -353,14 +354,14 @@ def _process_feature_notification(device, status, n, feature):
charge, lux, adc = _unpack('!BHH', n.data[:5])
# guesstimate the battery voltage, emphasis on 'guess'
# status_text = '%1.2fV' % (adc * 2.67793237653 / 0x0672)
status_text = _hidpp20.BATTERY_STATUS.discharging
status_text = _hidpp20_constants.BATTERY_STATUS.discharging
if n.address == 0x00:
status[_K.LIGHT_LEVEL] = None
status.set_battery_info(charge, None, status_text, None)
elif n.address == 0x10:
status[_K.LIGHT_LEVEL] = lux
if lux > 200:
status_text = _hidpp20.BATTERY_STATUS.recharging
status_text = _hidpp20_constants.BATTERY_STATUS.recharging
status.set_battery_info(charge, None, status_text, None)
elif n.address == 0x20:
if logger.isEnabledFor(logging.DEBUG):

View File

@ -22,7 +22,7 @@ import math
from struct import unpack as _unpack
from time import sleep as _sleep
from . import hidpp20 as _hidpp20
from . import hidpp20_constants as _hidpp20_constants
from .common import NamedInt as _NamedInt
from .common import NamedInts as _NamedInts
from .common import bytes2int as _bytes2int
@ -1416,7 +1416,7 @@ class ActionSettingRW:
def write(self, device, data_bytes):
def handler(device, n): # Called on notification events from the device
if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == _hidpp20.FEATURE.REPROG_CONTROLS_V4:
if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == _hidpp20_constants.FEATURE.REPROG_CONTROLS_V4:
if n.address == 0x00:
cids = _unpack('!HHHH', n.data[:8])
if not self.pressed and int(self.key.key) in cids: # trigger key pressed
@ -1478,11 +1478,11 @@ class RawXYProcessing:
self.keys = [] # the keys that can initiate processing
self.initiating_key = None # the key that did initiate processing
self.active = False
self.feature_offset = device.features[_hidpp20.FEATURE.REPROG_CONTROLS_V4]
self.feature_offset = device.features[_hidpp20_constants.FEATURE.REPROG_CONTROLS_V4]
assert self.feature_offset is not False
def handler(self, device, n): # Called on notification events from the device
if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == _hidpp20.FEATURE.REPROG_CONTROLS_V4:
if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == _hidpp20_constants.FEATURE.REPROG_CONTROLS_V4:
if n.address == 0x00:
cids = _unpack('!HHHH', n.data[:8])
## generalize to list of keys
@ -1550,7 +1550,7 @@ class RawXYProcessing:
def apply_all_settings(device):
if device.features and _hidpp20.FEATURE.HIRES_WHEEL in device.features:
if device.features and _hidpp20_constants.FEATURE.HIRES_WHEEL in device.features:
_sleep(0.2) # delay to try to get out of race condition with Linux HID++ driver
persister = getattr(device, 'persister', None)
sensitives = persister.get('_sensitive', {}) if persister else {}

View File

@ -28,6 +28,7 @@ from traceback import format_exc as _format_exc
from . import descriptors as _descriptors
from . import hidpp10_constants as _hidpp10_constants
from . import hidpp20 as _hidpp20
from . import hidpp20_constants as _hidpp20_constants
from . import special_keys as _special_keys
from .base import _HIDPP_Notification as _HIDPP_Notification
from .common import NamedInt as _NamedInt
@ -60,9 +61,9 @@ logger = logging.getLogger(__name__)
_DK = _hidpp10_constants.DEVICE_KIND
_R = _hidpp10_constants.REGISTERS
_F = _hidpp20.FEATURE
_F = _hidpp20_constants.FEATURE
_GG = _hidpp20.GESTURE
_GG = _hidpp20_constants.GESTURE
_GP = _hidpp20.PARAM
# Setting classes are used to control the settings that the Solaar GUI shows and manipulates.
@ -556,8 +557,8 @@ class ReportRate(_Setting):
def write(self, device, data_bytes):
# Host mode is required for report rate to be adjustable
if _hidpp20.get_onboard_mode(device) != _hidpp20.ONBOARD_MODES.MODE_HOST:
_hidpp20.set_onboard_mode(device, _hidpp20.ONBOARD_MODES.MODE_HOST)
if _hidpp20.get_onboard_mode(device) != _hidpp20_constants.ONBOARD_MODES.MODE_HOST:
_hidpp20.set_onboard_mode(device, _hidpp20_constants.ONBOARD_MODES.MODE_HOST)
return super().write(device, data_bytes)
class validator_class(_ChoicesV):
@ -602,8 +603,8 @@ class ExtendedReportRate(_Setting):
def write(self, device, data_bytes):
# Host mode is required for report rate to be adjustable
if _hidpp20.get_onboard_mode(device) != _hidpp20.ONBOARD_MODES.MODE_HOST:
_hidpp20.set_onboard_mode(device, _hidpp20.ONBOARD_MODES.MODE_HOST)
if _hidpp20.get_onboard_mode(device) != _hidpp20_constants.ONBOARD_MODES.MODE_HOST:
_hidpp20.set_onboard_mode(device, _hidpp20_constants.ONBOARD_MODES.MODE_HOST)
return super().write(device, data_bytes)
class validator_class(_ChoicesV):
@ -849,7 +850,7 @@ class MouseGesturesXY(_RawXYProcessing):
logger.info('mouse gesture notification %s', self.data)
payload = _pack('!' + (len(self.data) * 'h'), *self.data)
notification = _HIDPP_Notification(0, 0, 0, 0, payload)
_process_notification(self.device, self.device.status, notification, _hidpp20.FEATURE.MOUSE_GESTURE)
_process_notification(self.device, self.device.status, notification, _F.MOUSE_GESTURE)
self.fsmState = 'idle'
def move_action(self, dx, dy):
@ -1238,7 +1239,7 @@ class Gesture2Gestures(_BitFieldOMSetting):
feature = _F.GESTURE_2
rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20}
validator_options = {'om_method': _hidpp20.Gesture.enable_offset_mask}
choices_universe = _hidpp20.GESTURE
choices_universe = _hidpp20_constants.GESTURE
_labels = _GESTURE2_GESTURES_LABELS
class validator_class(_BitFieldOMV):
@ -1256,7 +1257,7 @@ class Gesture2Divert(_BitFieldOMSetting):
feature = _F.GESTURE_2
rw_options = {'read_fnid': 0x30, 'write_fnid': 0x40}
validator_options = {'om_method': _hidpp20.Gesture.diversion_offset_mask}
choices_universe = _hidpp20.GESTURE
choices_universe = _hidpp20_constants.GESTURE
_labels = _GESTURE2_GESTURES_LABELS
class validator_class(_BitFieldOMV):

View File

@ -173,8 +173,8 @@ class DeviceStatus(dict):
old_voltage, self[KEYS.BATTERY_VOLTAGE] = self.get(KEYS.BATTERY_VOLTAGE), voltage
charging = status in (
_hidpp20_constants.BATTERY_STATUS.recharging, _hidpp20_constants.BATTERY_STATUS.almost_full, _hidpp20_constants.BATTERY_STATUS.full,
_hidpp20_constants.BATTERY_STATUS.slow_recharge
_hidpp20_constants.BATTERY_STATUS.recharging, _hidpp20_constants.BATTERY_STATUS.almost_full,
_hidpp20_constants.BATTERY_STATUS.full, _hidpp20_constants.BATTERY_STATUS.slow_recharge
)
old_charging, self[KEYS.BATTERY_CHARGING] = self.get(KEYS.BATTERY_CHARGING), charging

View File

@ -20,13 +20,14 @@ from logitech_receiver import exceptions
from logitech_receiver import hidpp10 as _hidpp10
from logitech_receiver import hidpp10_constants as _hidpp10_constants
from logitech_receiver import hidpp20 as _hidpp20
from logitech_receiver import hidpp20_constants as _hidpp20_constants
from logitech_receiver import receiver as _receiver
from logitech_receiver import settings_templates as _settings_templates
from logitech_receiver.common import NamedInt as _NamedInt
from logitech_receiver.common import strhex as _strhex
from solaar import NAME, __version__
_F = _hidpp20.FEATURE
_F = _hidpp20_constants.FEATURE
def _print_receiver(receiver):
@ -142,11 +143,11 @@ def _print_device(dev, num=None):
for feature, index in dev.features.enumerate():
flags = dev.request(0x0000, feature.bytes(2))
flags = 0 if flags is None else ord(flags[1:2])
flags = _hidpp20.FEATURE_FLAG.flag_names(flags)
flags = _hidpp20_constants.FEATURE_FLAG.flag_names(flags)
version = dev.features.get_feature_version(int(feature))
version = version if version else 0
print(' %2d: %-22s {%04X} V%s %s ' % (index, feature, feature, version, ', '.join(flags)))
if feature == _hidpp20.FEATURE.HIRES_WHEEL:
if feature == _hidpp20_constants.FEATURE.HIRES_WHEEL:
wheel = _hidpp20.get_hires_wheel(dev)
if wheel:
multi, has_invert, has_switch, inv, res, target, ratchet = wheel
@ -163,7 +164,7 @@ def _print_device(dev, num=None):
print(' HID++ notification')
else:
print(' HID notification')
elif feature == _hidpp20.FEATURE.MOUSE_POINTER:
elif feature == _hidpp20_constants.FEATURE.MOUSE_POINTER:
mouse_pointer = _hidpp20.get_mouse_pointer_info(dev)
if mouse_pointer:
print(' DPI: %s' % mouse_pointer['dpi'])
@ -176,13 +177,13 @@ def _print_device(dev, num=None):
print(' Provide vertical tuning, trackball')
else:
print(' No vertical tuning, standard mice')
elif feature == _hidpp20.FEATURE.VERTICAL_SCROLLING:
elif feature == _hidpp20_constants.FEATURE.VERTICAL_SCROLLING:
vertical_scrolling_info = _hidpp20.get_vertical_scrolling_info(dev)
if vertical_scrolling_info:
print(' Roller type: %s' % vertical_scrolling_info['roller'])
print(' Ratchet per turn: %s' % vertical_scrolling_info['ratchet'])
print(' Scroll lines: %s' % vertical_scrolling_info['lines'])
elif feature == _hidpp20.FEATURE.HI_RES_SCROLLING:
elif feature == _hidpp20_constants.FEATURE.HI_RES_SCROLLING:
scrolling_mode, scrolling_resolution = _hidpp20.get_hi_res_scrolling_info(dev)
if scrolling_mode:
print(' Hi-res scrolling enabled')
@ -190,30 +191,30 @@ def _print_device(dev, num=None):
print(' Hi-res scrolling disabled')
if scrolling_resolution:
print(' Hi-res scrolling multiplier: %s' % scrolling_resolution)
elif feature == _hidpp20.FEATURE.POINTER_SPEED:
elif feature == _hidpp20_constants.FEATURE.POINTER_SPEED:
pointer_speed = _hidpp20.get_pointer_speed_info(dev)
if pointer_speed:
print(' Pointer Speed: %s' % pointer_speed)
elif feature == _hidpp20.FEATURE.LOWRES_WHEEL:
elif feature == _hidpp20_constants.FEATURE.LOWRES_WHEEL:
wheel_status = _hidpp20.get_lowres_wheel_status(dev)
if wheel_status:
print(' Wheel Reports: %s' % wheel_status)
elif feature == _hidpp20.FEATURE.NEW_FN_INVERSION:
elif feature == _hidpp20_constants.FEATURE.NEW_FN_INVERSION:
inversion = _hidpp20.get_new_fn_inversion(dev)
if inversion:
inverted, default_inverted = inversion
print(' Fn-swap:', 'enabled' if inverted else 'disabled')
print(' Fn-swap default:', 'enabled' if default_inverted else 'disabled')
elif feature == _hidpp20.FEATURE.HOSTS_INFO:
elif feature == _hidpp20_constants.FEATURE.HOSTS_INFO:
host_names = _hidpp20.get_host_names(dev)
for host, (paired, name) in host_names.items():
print(' Host %s (%s): %s' % (host, 'paired' if paired else 'unpaired', name))
elif feature == _hidpp20.FEATURE.DEVICE_NAME:
elif feature == _hidpp20_constants.FEATURE.DEVICE_NAME:
print(' Name: %s' % _hidpp20.get_name(dev))
print(' Kind: %s' % _hidpp20.get_kind(dev))
elif feature == _hidpp20.FEATURE.DEVICE_FRIENDLY_NAME:
elif feature == _hidpp20_constants.FEATURE.DEVICE_FRIENDLY_NAME:
print(' Friendly Name: %s' % _hidpp20.get_friendly_name(dev))
elif feature == _hidpp20.FEATURE.DEVICE_FW_VERSION:
elif feature == _hidpp20_constants.FEATURE.DEVICE_FW_VERSION:
for fw in _hidpp20.get_firmware(dev):
extras = _strhex(fw.extras) if fw.extras else ''
print(' Firmware: %s %s %s %s' % (fw.kind, fw.name, fw.version, extras))
@ -221,12 +222,12 @@ def _print_device(dev, num=None):
if ids:
unitId, modelId, tid_map = ids
print(' Unit ID: %s Model ID: %s Transport IDs: %s' % (unitId, modelId, tid_map))
elif feature == _hidpp20.FEATURE.REPORT_RATE or feature == _hidpp20.FEATURE.EXTENDED_ADJUSTABLE_REPORT_RATE:
elif feature == _hidpp20_constants.FEATURE.REPORT_RATE or feature == _hidpp20_constants.FEATURE.EXTENDED_ADJUSTABLE_REPORT_RATE:
print(' Report Rate: %s' % _hidpp20.get_polling_rate(dev))
elif feature == _hidpp20.FEATURE.REMAINING_PAIRING:
elif feature == _hidpp20_constants.FEATURE.REMAINING_PAIRING:
print(' Remaining Pairings: %d' % _hidpp20.get_remaining_pairing(dev))
elif feature == _hidpp20.FEATURE.ONBOARD_PROFILES:
if _hidpp20.get_onboard_mode(dev) == _hidpp20.ONBOARD_MODES.MODE_HOST:
elif feature == _hidpp20_constants.FEATURE.ONBOARD_PROFILES:
if _hidpp20.get_onboard_mode(dev) == _hidpp20_constants.ONBOARD_MODES.MODE_HOST:
mode = 'Host'
else:
mode = 'On-Board'
@ -252,9 +253,9 @@ def _print_device(dev, num=None):
print(' Has %d reprogrammable keys:' % len(dev.keys))
for k in dev.keys:
# TODO: add here additional variants for other REPROG_CONTROLS
if dev.keys.keyversion == _hidpp20.FEATURE.REPROG_CONTROLS_V2:
if dev.keys.keyversion == _hidpp20_constants.FEATURE.REPROG_CONTROLS_V2:
print(' %2d: %-26s => %-27s %s' % (k.index, k.key, k.default_task, ', '.join(k.flags)))
if dev.keys.keyversion == _hidpp20.FEATURE.REPROG_CONTROLS_V4:
if dev.keys.keyversion == _hidpp20_constants.FEATURE.REPROG_CONTROLS_V4:
print(' %2d: %-26s, default: %-27s => %-26s' % (k.index, k.key, k.default_task, k.mapped_to))
gmask_fmt = ','.join(k.group_mask)
gmask_fmt = gmask_fmt if gmask_fmt else 'empty'