receiver: simpler way to create setting information for device descriptors

This commit is contained in:
Vinícius 2020-06-18 00:27:15 -03:00 committed by Peter F. Patel-Schneider
parent e69c4c6b4f
commit 6d16462988
2 changed files with 97 additions and 143 deletions

View File

@ -11,9 +11,9 @@ Feature | ID | Status | Notes
`ROOT` | `0x0000` | :heavy_check_mark: | System `ROOT` | `0x0000` | :heavy_check_mark: | System
`FEATURE_SET` | `0x0001` | :heavy_check_mark: | System `FEATURE_SET` | `0x0001` | :heavy_check_mark: | System
`FEATURE_INFO` | `0x0002` | :heavy_check_mark: | System `FEATURE_INFO` | `0x0002` | :heavy_check_mark: | System
`DEVICE_FW_VERSION` | `0x0003` | :heavy_check_mark: | `get_firmware()`, read only `DEVICE_FW_VERSION` | `0x0003` | :heavy_check_mark: | `get_firmware`, read only
`DEVICE_UNIT_ID` | `0x0004` | :x: | `DEVICE_UNIT_ID` | `0x0004` | :x: |
`DEVICE_NAME` | `0x0005` | :heavy_check_mark: | `get_kind()`, `get_name()`, read only `DEVICE_NAME` | `0x0005` | :heavy_check_mark: | `get_kind`, `get_name`, read only
`DEVICE_GROUPS` | `0x0006` | :x: | `DEVICE_GROUPS` | `0x0006` | :x: |
`DEVICE_FRIENDLY_NAME` | `0x0007` | :x: | `DEVICE_FRIENDLY_NAME` | `0x0007` | :x: |
`KEEP_ALIVE` | `0x0008` | :x: | `KEEP_ALIVE` | `0x0008` | :x: |
@ -25,8 +25,8 @@ Feature | ID | Status | Notes
`DFUCONTROL_UNSIGNED` | `0x00C1` | :x: | `DFUCONTROL_UNSIGNED` | `0x00C1` | :x: |
`DFUCONTROL_SIGNED` | `0x00C2` | :x: | `DFUCONTROL_SIGNED` | `0x00C2` | :x: |
`DFU` | `0x00D0` | :x: | `DFU` | `0x00D0` | :x: |
`BATTERY_STATUS` | `0x1000` | :heavy_check_mark: | `get_battery()`, read only `BATTERY_STATUS` | `0x1000` | :heavy_check_mark: | `get_battery`, read only
`BATTERY_VOLTAGE` | `0x1001` | :heavy_check_mark: | `get_voltage()`, read only `BATTERY_VOLTAGE` | `0x1001` | :heavy_check_mark: | `get_voltage`, read only
`CHARGING_CONTROL` | `0x1010` | :x: | `CHARGING_CONTROL` | `0x1010` | :x: |
`LED_CONTROL` | `0x1300` | :x: | `LED_CONTROL` | `0x1300` | :x: |
`GENERIC_TEST` | `0x1800` | :x: | `GENERIC_TEST` | `0x1800` | :x: |
@ -36,15 +36,15 @@ Feature | ID | Status | Notes
`CHANGE_HOST` | `0x1814` | :x: | `CHANGE_HOST` | `0x1814` | :x: |
`HOSTS_INFO` | `0x1815` | :x: | `HOSTS_INFO` | `0x1815` | :x: |
`BACKLIGHT` | `0x1981` | :x: | `BACKLIGHT` | `0x1981` | :x: |
`BACKLIGHT2` | `0x1982` | :heavy_check_mark: | `_feature_backlight2()` `BACKLIGHT2` | `0x1982` | :heavy_check_mark: | `_feature_backlight2`
`BACKLIGHT3` | `0x1983` | :x: | `BACKLIGHT3` | `0x1983` | :x: |
`PRESENTER_CONTROL` | `0x1A00` | :x: | `PRESENTER_CONTROL` | `0x1A00` | :x: |
`SENSOR_3D` | `0x1A01` | :x: | `SENSOR_3D` | `0x1A01` | :x: |
`REPROG_CONTROLS` | `0x1B00` | :heavy_plus_sign: | `get_keys()`, only listing `REPROG_CONTROLS` | `0x1B00` | :heavy_plus_sign: | `get_keys`, only listing
`REPROG_CONTROLS_V2` | `0x1B01` | :x: | `REPROG_CONTROLS_V2` | `0x1B01` | :x: |
`REPROG_CONTROLS_V2_2` | `0x1B02` | :x: | `REPROG_CONTROLS_V2_2` | `0x1B02` | :x: |
`REPROG_CONTROLS_V3` | `0x1B03` | :x: | `REPROG_CONTROLS_V3` | `0x1B03` | :x: |
`REPROG_CONTROLS_V4` | `0x1B04` | :heavy_plus_sign: | `get_keys()`, _feature_reprogrammable_keys() `REPROG_CONTROLS_V4` | `0x1B04` | :heavy_plus_sign: | `get_keys`, _feature_reprogrammable_keys
`REPORT_HID_USAGE` | `0x1BC0` | :x: | `REPORT_HID_USAGE` | `0x1BC0` | :x: |
`PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | :x: | `PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | :x: |
`WIRELESS_DEVICE_STATUS` | `0x1D4B` | :x: | status reporting from device `WIRELESS_DEVICE_STATUS` | `0x1D4B` | :x: | status reporting from device
@ -54,26 +54,26 @@ Feature | ID | Status | Notes
`LEFT_RIGHT_SWAP` | `0x2001` | :x: | `LEFT_RIGHT_SWAP` | `0x2001` | :x: |
`SWAP_BUTTON_CANCEL` | `0x2005` | :x: | `SWAP_BUTTON_CANCEL` | `0x2005` | :x: |
`POINTER_AXIS_ORIENTATION` | `0x2006` | :x: | `POINTER_AXIS_ORIENTATION` | `0x2006` | :x: |
`VERTICAL_SCROLLING` | `0x2100` | :heavy_check_mark: | `get_vertical_scrolling_info()`, read only `VERTICAL_SCROLLING` | `0x2100` | :heavy_check_mark: | `get_vertical_scrolling_info`, read only
`SMART_SHIFT` | `0x2110` | :heavy_check_mark: | `_feature_smart_shift()` `SMART_SHIFT` | `0x2110` | :heavy_check_mark: | `_feature_smart_shift`
`HI_RES_SCROLLING` | `0x2120` | :heavy_check_mark: | `get_hi_res_scrolling_info()`, `_feature_hi_res_scroll()` `HI_RES_SCROLLING` | `0x2120` | :heavy_check_mark: | `get_hi_res_scrolling_info`, `_feature_hi_res_scroll`
`HIRES_WHEEL` | `0x2121` | :heavy_check_mark: | `get_hires_wheel()`, `_feature_hires_smooth_invert()`, `_feature_hires_smooth_resolution()` `HIRES_WHEEL` | `0x2121` | :heavy_check_mark: | `get_hires_wheel`, `_feature_hires_smooth_invert`, `_feature_hires_smooth_resolution`
`LOWRES_WHEEL` | `0x2130` | :heavy_check_mark: | `get_lowres_wheel_status()`, `_feature_lowres_smooth_scroll()` `LOWRES_WHEEL` | `0x2130` | :heavy_check_mark: | `get_lowres_wheel_status`, `_feature_lowres_smooth_scroll`
`THUMB_WHEEL` | `0x2150` | :x: | `THUMB_WHEEL` | `0x2150` | :x: |
`MOUSE_POINTER` | `0x2200` | :heavy_check_mark: | `get_mouse_pointer_info()`, read only `MOUSE_POINTER` | `0x2200` | :heavy_check_mark: | `get_mouse_pointer_info`, read only
`ADJUSTABLE_DPI` | `0x2201` | :heavy_check_mark: | `_feature_adjustable_dpi()` `ADJUSTABLE_DPI` | `0x2201` | :heavy_check_mark: | `_feature_adjustable_dpi`
`POINTER_SPEED` | `0x2205` | :heavy_check_mark: | `get_pointer_speed_info()`, `_feature_pointer_speed()` `POINTER_SPEED` | `0x2205` | :heavy_check_mark: | `get_pointer_speed_info`, `_feature_pointer_speed`
`ANGLE_SNAPPING` | `0x2230` | :x: | `ANGLE_SNAPPING` | `0x2230` | :x: |
`SURFACE_TUNING` | `0x2240` | :x: | `SURFACE_TUNING` | `0x2240` | :x: |
`HYBRID_TRACKING` | `0x2400` | :x: | `HYBRID_TRACKING` | `0x2400` | :x: |
`FN_INVERSION` | `0x40A0` | :heavy_check_mark: | `_feature_fn_swap()` `FN_INVERSION` | `0x40A0` | :heavy_check_mark: | `_feature_fn_swap`
`NEW_FN_INVERSION` | `0x40A2` | :heavy_check_mark: | `_feature_new_fn_swap()` `NEW_FN_INVERSION` | `0x40A2` | :heavy_check_mark: | `_feature_new_fn_swap`
`K375S_FN_INVERSION` | `0x40A3` | :heavy_check_mark: | `_feature_k375s_fn_swap()` `K375S_FN_INVERSION` | `0x40A3` | :heavy_check_mark: | `_feature_k375s_fn_swap`
`ENCRYPTION` | `0x4100` | :x: | `ENCRYPTION` | `0x4100` | :x: |
`LOCK_KEY_STATE` | `0x4220` | :x: | `LOCK_KEY_STATE` | `0x4220` | :x: |
`SOLAR_DASHBOARD` | `0x4301` | :x: | `SOLAR_DASHBOARD` | `0x4301` | :x: |
`KEYBOARD_LAYOUT` | `0x4520` | :x: | read only `KEYBOARD_LAYOUT` | `0x4520` | :x: | read only
`KEYBOARD_DISABLE` | `0x4521` | :x: | `KEYBOARD_DISABLE_KEYS` | `0x4521` | :heavy_check_mark: | `_feature_disable_keyboard_keys`
`KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | :x: | `KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | :x: |
`DUALPLATFORM` | `0x4530` | :x: | `DUALPLATFORM` | `0x4530` | :x: |
`MULTIPLATFORM` | `0x4531` | :x: | `MULTIPLATFORM` | `0x4531` | :x: |
@ -95,7 +95,7 @@ Feature | ID | Status | Notes
`MKEYS` | `0x8020` | :x: | `MKEYS` | `0x8020` | :x: |
`MR` | `0x8030` | :x: | `MR` | `0x8030` | :x: |
`BRIGHTNESS_CONTROL` | `0x8040` | :x: | `BRIGHTNESS_CONTROL` | `0x8040` | :x: |
`REPORT_RATE` | `0x8060` | :x: | `REPORT_RATE` | `0x8060` | :x: | in progress
`COLOR_LED_EFFECTS` | `0x8070` | :x: | `COLOR_LED_EFFECTS` | `0x8070` | :x: |
`RGB_EFFECTS` | `0X8071` | :x: | `RGB_EFFECTS` | `0X8071` | :x: |
`PER_KEY_LIGHTING` | `0x8080` | :x: | `PER_KEY_LIGHTING` | `0x8080` | :x: |
@ -121,14 +121,16 @@ lib/logitech_receiver/hidpp20.py
In most cases it should suffice to only implement the settable feature In most cases it should suffice to only implement the settable feature
interface for each setting in the feature. That will add one or more interface for each setting in the feature. That will add one or more
widgets in the Solaar main window to show and change the feature, widgets in the Solaar main window to show and change the setting,
store and restore changed settings, and will permit storing and restoring changed settings, and
output the feature settings in `solaar show`. will output the feature settings in `solaar show`.
Adding a setting involves several steps, described here and illustrated by the pointer speed setting. Adding a setting implementation involves several steps, described here and
illustrated by the pointer speed setting implementation.
Add a name, a label, and a description for the setting in the common strings section. First add a name, a label, and a description for the setting in the common strings section.
The name is used in the persistent settings structure to store and restore changed settings. The name is used in the persistent settings structure to store and restore changed settings and
should be a valid Python identifier. (Some older settings have dashes.)
The label is displayed in the Solaar main window and the description is used as a tooltip there. The label is displayed in the Solaar main window and the description is used as a tooltip there.
The label and description should be specified as translatable strings. The label and description should be specified as translatable strings.
@ -136,17 +138,23 @@ The label and description should be specified as translatable strings.
_POINTER_SPEED = ('pointer_speed', _("Sensitivity (Pointer Speed)"), _("How fast the pointer moves")) _POINTER_SPEED = ('pointer_speed', _("Sensitivity (Pointer Speed)"), _("How fast the pointer moves"))
``` ```
Create the feature interface for the setting. There are several possible Implement a register interface for the setting (if you are very brave and
some devices have a register interface for the setting).
Register interfaces cannot be auto-discovered and need to be stated in descriptors.py
for each device with the register interface.
Implement a feature interface for the setting. There are several possible kinds of
feature interfaces, ranging from simple toggles, to ranges, to fixed lists, to feature interfaces, ranging from simple toggles, to ranges, to fixed lists, to
dynamic lists, each created by a macro function. Pointer speed is a setting dynamic choices, to maps of dynamic choices, each created by a macro function.
Pointer speed is a setting
whose values are integers in a range so `feature_range` is used. whose values are integers in a range so `feature_range` is used.
The arguments to this macro are The arguments to this macro are
an identifier of the setting (in simple cases using the setting name is easiest), the name of the setting (use the name from the common strings tuple),
the HID++ 2.0 feature ID for the setting (from the FEATURE structure in hidpp20.py), the HID++ 2.0 feature ID for the setting (from the FEATURE structure in hidpp20.py),
the minimum and maximum values for the setting, the minimum and maximum values for the setting,
the HID++ 2.0 function IDs to read and write the setting, the HID++ 2.0 function IDs to read and write the setting (left-shifted four bits),
the byte size of the setting value, the byte size of the setting value,
a label and description for the setting, a label and description for the setting (from the common strings tuple),
and which kinds of devices can have this setting. and which kinds of devices can have this setting.
(This last is no longer used because keyboards with integrated pointers only (This last is no longer used because keyboards with integrated pointers only
report that they are keyboards.) report that they are keyboards.)
@ -170,14 +178,17 @@ Settings where the choices are determined from the device
need an auxiliary function to receive and decipher the permissable choices. need an auxiliary function to receive and decipher the permissable choices.
See `_feature_adjustable_dpi_choices` for an example. See `_feature_adjustable_dpi_choices` for an example.
Add the setting identifier to _SETTINGS_LIST, Add an element to _SETTINGS_TABLE with
to the RegisterSettings list as a setting with no register implementation, the setting name (from the common strings),
and to the FeatureSettings list with its implementation. the feature ID (if any),
the feature implementation (if any),
Add the setting's name and feature to check_feature_settings (and feature the register implementation (if any).
interface identifier if different from the name) so that devices will be and
probed to see if they support the setting. the identifier for the setting implementation if different from the setting name.
The identifier is used in descriptors.py to say that a device has the register or feature implementation.
The identifier can be the same as the setting name if there is only one implementation for the setting.
This table is used to generate the data structures for describing devices in descriptors.py
and is also used to auto-discover feature implementations.
``` ```
check_feature(_POINTER_SPEED[0], _F.POINTER_SPEED) _S( _POINTER_SPEED[0], _F.POINTER_SPEED, _feature_pointer_speed ),
``` ```

View File

@ -178,41 +178,33 @@ def feature_range(name, feature, min_value, max_value,
return _Setting(name, rw, validator, feature=feature, kind=_KIND.range, label=label, description=description, device_kind=device_kind) return _Setting(name, rw, validator, feature=feature, kind=_KIND.range, label=label, description=description, device_kind=device_kind)
# #
# common strings for settings # common strings for settings - name, string to display in main window, tool tip for main window
# #
_SMOOTH_SCROLL = ('smooth-scroll', _("Smooth Scrolling"), _HAND_DETECTION = ('hand-detection', _("Hand Detection"), _("Turn on illumination when the hands hover over the keyboard."))
_SMOOTH_SCROLL = ('smooth-scroll', _("Smooth Scrolling"), _("High-sensitivity mode for vertical scroll with the wheel."))
_SIDE_SCROLL = ('side-scroll', _("Side Scrolling"), _("When disabled, pushing the wheel sideways sends custom button events\n"
"instead of the standard side-scrolling events."))
_HI_RES_SCROLL = ('hi-res-scroll', _("High Resolution Scrolling"),
_("High-sensitivity mode for vertical scroll with the wheel.")) _("High-sensitivity mode for vertical scroll with the wheel."))
_LOW_RES_SCROLL = ('lowres-smooth-scroll', _("HID++ Scrolling"), _LOW_RES_SCROLL = ('lowres-smooth-scroll', _("HID++ Scrolling"),
_("HID++ mode for vertical scroll with the wheel.")) _("HID++ mode for vertical scroll with the wheel."))
_HI_RES_SCROLL = ('hi-res-scroll', _("High Resolution Scrolling"),
_("High-sensitivity mode for vertical scroll with the wheel."))
_HIRES_INV = ('hires-smooth-invert', _("High Resolution Wheel Invert"), _HIRES_INV = ('hires-smooth-invert', _("High Resolution Wheel Invert"),
_("High-sensitivity wheel invert mode for vertical scroll.")) _("High-sensitivity wheel invert mode for vertical scroll."))
_HIRES_RES = ('hires-smooth-resolution', _("Wheel Resolution"), _HIRES_RES = ('hires-smooth-resolution', _("Wheel Resolution"),
_("High-sensitivity mode for vertical scroll with the wheel.")) _("High-sensitivity mode for vertical scroll with the wheel."))
_SIDE_SCROLL = ('side-scroll', _("Side Scrolling"), _FN_SWAP = ('fn-swap', _("Swap Fx function"), _("When set, the F1..F12 keys will activate their special function,\n"
_("When disabled, pushing the wheel sideways sends custom button events\n"
"instead of the standard side-scrolling events."))
_DPI = ('dpi', _("Sensitivity (DPI)"), None)
_POINTER_SPEED = ('pointer_speed', _("Sensitivity (Pointer Speed)"), None)
_FN_SWAP = ('fn-swap', _("Swap Fx function"),
_("When set, the F1..F12 keys will activate their special function,\n"
"and you must hold the FN key to activate their standard function.") "and you must hold the FN key to activate their standard function.")
+ '\n\n' + + '\n\n' +
_("When unset, the F1..F12 keys will activate their standard function,\n" _("When unset, the F1..F12 keys will activate their standard function,\n"
"and you must hold the FN key to activate their special function.")) "and you must hold the FN key to activate their special function."))
_DISABLE_KEYS = ('disable-keyboard-keys', _("Disable keys"), _("Disable specific keyboard keys.")) _DPI = ('dpi', _("Sensitivity (DPI)"), None)
_HAND_DETECTION = ('hand-detection', _("Hand Detection"), _POINTER_SPEED = ('pointer_speed', _("Sensitivity (Pointer Speed)"), None)
_("Turn on illumination when the hands hover over the keyboard.")) _SMART_SHIFT = ('smart-shift', _("Smart Shift"), _("Automatically switch the mouse wheel between ratchet and freespin mode.\n"
_BACKLIGHT = ('backlight', _("Backlight"),
_("Turn illumination on or off on keyboard."))
_SMART_SHIFT = ('smart-shift', _("Smart Shift"),
_("Automatically switch the mouse wheel between ratchet and freespin mode.\n"
"The mouse wheel is always free at 0, and always locked at 50")) "The mouse wheel is always free at 0, and always locked at 50"))
_BACKLIGHT = ('backlight', _("Backlight"), _("Turn illumination on or off on keyboard."))
_REPROGRAMMABLE_KEYS = ('reprogrammable-keys', _("Actions"), _("Change the action for the key")) _REPROGRAMMABLE_KEYS = ('reprogrammable-keys', _("Actions"), _("Change the action for the key"))
_DISABLE_KEYS = ('disable-keyboard-keys', _("Disable keys"), _("Disable specific keyboard keys."))
# #
# #
@ -426,65 +418,32 @@ def _feature_disable_keyboard_keys():
# #
from collections import namedtuple from collections import namedtuple
_SETTINGS_LIST = namedtuple('_SETTINGS_LIST', [
'fn_swap',
'new_fn_swap',
'k375s_fn_swap',
'smooth_scroll',
'hi_res_scroll',
'lowres_smooth_scroll',
'hires_smooth_invert',
'hires_smooth_resolution',
'side_scroll',
'dpi',
'pointer_speed',
'hand_detection',
'backlight',
'typing_illumination',
'smart_shift',
'reprogrammable_keys',
'disable_keyboard_keys',
])
del namedtuple
RegisterSettings = _SETTINGS_LIST( def _S(name, featureID=None, featureFn=None, registerFn=None, identifier=None):
fn_swap=_register_fn_swap, return ( name, featureID, featureFn, registerFn, identifier if identifier else name.replace('-','_') )
new_fn_swap=None,
k375s_fn_swap=None, _SETTINGS_TABLE = [
smooth_scroll=_register_smooth_scroll, _S( _HAND_DETECTION[0], registerFn=_register_hand_detection ),
hi_res_scroll=None, _S( _SMOOTH_SCROLL[0], registerFn=_register_smooth_scroll ),
lowres_smooth_scroll=None, _S( _SIDE_SCROLL[0], registerFn=_register_side_scroll ),
hires_smooth_invert=None, _S( _HI_RES_SCROLL[0], _F.HI_RES_SCROLLING, _feature_hi_res_scroll ),
hires_smooth_resolution=None, _S( _LOW_RES_SCROLL[0], _F.LOWRES_WHEEL, _feature_lowres_smooth_scroll ),
side_scroll=_register_side_scroll, _S( _HIRES_INV[0], _F.HIRES_WHEEL, _feature_hires_smooth_invert ),
dpi=_register_dpi, _S( _HIRES_RES[0], _F.HIRES_WHEEL, _feature_hires_smooth_resolution ),
pointer_speed=None, _S( _FN_SWAP[0], _F.FN_INVERSION, _feature_fn_swap, registerFn=_register_fn_swap ),
hand_detection=_register_hand_detection, _S( _FN_SWAP[0], _F.NEW_FN_INVERSION, _feature_new_fn_swap, identifier='new_fn_swap' ),
backlight=None, _S( _FN_SWAP[0], _F.K375S_FN_INVERSION, _feature_k375s_fn_swap, identifier='k375s_fn_swap' ),
typing_illumination=None, _S( _DPI[0], _F.ADJUSTABLE_DPI, _feature_adjustable_dpi, registerFn=_register_dpi ),
smart_shift=None, _S( _POINTER_SPEED[0], _F.POINTER_SPEED, _feature_pointer_speed ),
reprogrammable_keys=None, _S( _SMART_SHIFT[0], _F.SMART_SHIFT, _feature_smart_shift ),
disable_keyboard_keys=None, _S( _BACKLIGHT[0], _F.BACKLIGHT2, _feature_backlight2 ),
) _S( _REPROGRAMMABLE_KEYS[0], _F.REPROG_CONTROLS_V4, _feature_reprogrammable_keys ),
FeatureSettings = _SETTINGS_LIST( _S( _DISABLE_KEYS[0], _F.KEYBOARD_DISABLE_KEYS, _feature_disable_keyboard_keys ),
fn_swap=_feature_fn_swap, ]
new_fn_swap=_feature_new_fn_swap,
k375s_fn_swap=_feature_k375s_fn_swap, _SETTINGS_LIST = namedtuple('_SETTINGS_LIST',[s[4] for s in _SETTINGS_TABLE])
smooth_scroll=None, RegisterSettings = _SETTINGS_LIST._make([s[3] for s in _SETTINGS_TABLE])
hi_res_scroll=_feature_hi_res_scroll, FeatureSettings = _SETTINGS_LIST._make([s[2] for s in _SETTINGS_TABLE])
lowres_smooth_scroll=_feature_lowres_smooth_scroll,
hires_smooth_invert=_feature_hires_smooth_invert,
hires_smooth_resolution=_feature_hires_smooth_resolution,
side_scroll=None,
dpi=_feature_adjustable_dpi,
pointer_speed=_feature_pointer_speed,
hand_detection=None,
backlight=_feature_backlight2,
typing_illumination=None,
smart_shift=_feature_smart_shift,
reprogrammable_keys=_feature_reprogrammable_keys,
disable_keyboard_keys=_feature_disable_keyboard_keys,
)
del _SETTINGS_LIST del _SETTINGS_LIST
@ -500,25 +459,19 @@ def check_feature_settings(device, already_known):
if device.protocol and device.protocol < 2.0: if device.protocol and device.protocol < 2.0:
return False return False
def check_feature(name, featureId, field_name=None): def check_feature(name, featureId, featureFn):
""" """
:param name: user-visible setting name. :param name: name for the setting
:param featureId: the numeric Feature ID for this setting. :param featureId: the numeric Feature ID for this setting implementation
:param field_name: override the FeatureSettings name if it is :param featureFn: the function for this setting implementation
different from the user-visible setting name. Useful if there
are multiple features for the same setting.
""" """
if not featureId in device.features: if not featureId in device.features:
return return
if any(s.name == name for s in already_known): if any(s.name == name for s in already_known):
return return
if not field_name:
# Convert user-visible settings name for FeatureSettings
field_name = name.replace('-', '_')
feature = getattr(FeatureSettings, field_name)()
try: try:
detected = feature(device) detected = featureFn()(device)
if _log.isEnabledFor(_DEBUG): if _log.isEnabledFor(_DEBUG):
_log.debug("check_feature[%s] detected %s", featureId, detected) _log.debug("check_feature[%s] detected %s", featureId, detected)
if detected: if detected:
@ -526,17 +479,7 @@ def check_feature_settings(device, already_known):
except Exception as reason: except Exception as reason:
_log.error("check_feature[%s] inconsistent feature %s", featureId, reason) _log.error("check_feature[%s] inconsistent feature %s", featureId, reason)
check_feature(_HI_RES_SCROLL[0], _F.HI_RES_SCROLLING) for name, featureId, featureFn, _, _ in _SETTINGS_TABLE :
check_feature(_LOW_RES_SCROLL[0], _F.LOWRES_WHEEL) if featureId and featureFn:
check_feature(_HIRES_INV[0], _F.HIRES_WHEEL, "hires_smooth_invert") check_feature(name, featureId, featureFn)
check_feature(_HIRES_RES[0], _F.HIRES_WHEEL, "hires_smooth_resolution")
check_feature(_FN_SWAP[0], _F.FN_INVERSION)
check_feature(_FN_SWAP[0], _F.NEW_FN_INVERSION, 'new_fn_swap')
check_feature(_FN_SWAP[0], _F.K375S_FN_INVERSION, 'k375s_fn_swap')
check_feature(_DPI[0], _F.ADJUSTABLE_DPI)
check_feature(_POINTER_SPEED[0], _F.POINTER_SPEED)
check_feature(_SMART_SHIFT[0], _F.SMART_SHIFT)
check_feature(_BACKLIGHT[0], _F.BACKLIGHT2)
check_feature(_REPROGRAMMABLE_KEYS[0], _F.REPROG_CONTROLS_V4)
check_feature(_DISABLE_KEYS[0], _F.KEYBOARD_DISABLE_KEYS, 'disable_keyboard_keys')
return True return True