From c464e049bf05605f40c7c9b51140f85c35d35c21 Mon Sep 17 00:00:00 2001 From: Daniel Pavel Date: Sat, 29 Jun 2013 20:54:06 +0200 Subject: [PATCH] allow settings to be bound to certain device types avoids stuff like smooth-scroll being attached to a keyboard --- lib/logitech/unifying_receiver/descriptors.py | 18 +++++++++++------ lib/logitech/unifying_receiver/settings.py | 20 +++++++++++-------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/logitech/unifying_receiver/descriptors.py b/lib/logitech/unifying_receiver/descriptors.py index 3b22391c..8b540aac 100644 --- a/lib/logitech/unifying_receiver/descriptors.py +++ b/lib/logitech/unifying_receiver/descriptors.py @@ -27,25 +27,31 @@ _FN_SWAP = ('fn-swap', 'Swap Fx function', # using Features def _register_fn_swap(register=0x09, true_value=b'\x00\x01', mask=b'\x00\x01'): return _settings.register_toggle(_FN_SWAP[0], register, true_value=true_value, mask=mask, - label=_FN_SWAP[1], description=_FN_SWAP[2]) + label=_FN_SWAP[1], description=_FN_SWAP[2], + device_kind=_hidpp10.DEVICE_KIND.keyboard) def _register_smooth_scroll(register=0x01, true_value=0x40, mask=0x40): return _settings.register_toggle(_SMOOTH_SCROLL[0], register, true_value=true_value, mask=mask, - label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2]) + label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2], + device_kind=_hidpp10.DEVICE_KIND.mouse) +_PERFORMANCE_MX_DPIS = _NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100)) def _register_dpi(register=0x63, choices=None): return _settings.register_choices(_DPI[0], register, choices, - label=_DPI[1], description=_DPI[2]) + label=_DPI[1], description=_DPI[2], + device_kind=_hidpp10.DEVICE_KIND.mouse) def _feature_fn_swap(): return _settings.feature_toggle(_FN_SWAP[0], _hidpp20.FEATURE.FN_INVERSION, write_returns_value=True, - label=_FN_SWAP[1], description=_FN_SWAP[2]) + label=_FN_SWAP[1], description=_FN_SWAP[2], + device_kind=_hidpp10.DEVICE_KIND.keyboard) def check_features(device, already_known): + """Try to auto-detect device settings by the HID++ 2.0 features they have.""" if device.protocol is not None and device.protocol < 2.0: return if not any(s.name == _FN_SWAP[0] for s in already_known) and _hidpp20.FEATURE.FN_INVERSION in device.features: @@ -72,7 +78,7 @@ def _D(name, codename=None, kind=None, product_id=None, protocol=None, registers assert kind is not None, "descriptor for %s does not have 'kind' set" % name # heuristic: the codename is the last word in the device name - if codename is None: + if codename is None and ' ' in name: codename = name.split(' ')[-1] assert codename is not None, "descriptor for %s does not have codename set" % name @@ -196,7 +202,7 @@ _D('Anywhere Mouse MX', codename='Anywhere MX') _D('Performance Mouse MX', codename='Performance MX', protocol=1.0, registers={'battery_charge': -0x0D, 'battery_status': 0x07, 'leds': 0x51}, settings=[ - _register_dpi(choices=_NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))), + _register_dpi(choices=_PERFORMANCE_MX_DPIS), ], ) diff --git a/lib/logitech/unifying_receiver/settings.py b/lib/logitech/unifying_receiver/settings.py index 6c34a78d..07461523 100644 --- a/lib/logitech/unifying_receiver/settings.py +++ b/lib/logitech/unifying_receiver/settings.py @@ -16,14 +16,17 @@ from .common import NamedInt as _NamedInt, NamedInts as _NamedInts KIND = _NamedInts(toggle=0x1, choice=0x02, range=0x12) class _Setting(object): - __slots__ = ['name', 'label', 'description', 'kind', 'persister', + """A setting descriptor. + Needs to be instantiated for each specific device.""" + __slots__ = ['name', 'label', 'description', 'kind', 'persister', 'device_kind', '_rw', '_validator', '_device', '_value'] - def __init__(self, name, rw, validator, kind=None, label=None, description=None): + def __init__(self, name, rw, validator, kind=None, label=None, description=None, device_kind=None): assert name self.name = name self.label = label or name self.description = description + self.device_kind = device_kind self._rw = rw self._validator = validator @@ -34,6 +37,7 @@ class _Setting(object): def __call__(self, device): assert not hasattr(self, '_value') + assert self.device_kind is None or self.device_kind == device.kind o = _copy(self) o._value = None o._device = device # _proxy(device) @@ -213,26 +217,26 @@ class _ChoicesValidator(object): def register_toggle(name, register, true_value=_BooleanValidator.default_true, false_value=_BooleanValidator.default_false, mask=_BooleanValidator.default_mask, write_returns_value=False, - label=None, description=None): + label=None, description=None, device_kind=None): rw = _RegisterRW(register) validator = _BooleanValidator(true_value=true_value, false_value=false_value, mask=mask, write_returns_value=write_returns_value) - return _Setting(name, rw, validator, label=label, description=description) + return _Setting(name, rw, validator, label=label, description=description, device_kind=device_kind) def register_choices(name, register, choices, kind=KIND.choice, write_returns_value=False, - label=None, description=None): + label=None, description=None, device_kind=None): assert choices rw = _RegisterRW(register) validator = _ChoicesValidator(choices, write_returns_value=write_returns_value) - return _Setting(name, rw, validator, kind=kind, label=label, description=description) + return _Setting(name, rw, validator, kind=kind, label=label, description=description, device_kind=device_kind) def feature_toggle(name, feature, read_function_id=_FeatureRW.default_read_fnid, write_function_id=_FeatureRW.default_write_fnid, true_value=_BooleanValidator.default_true, false_value=_BooleanValidator.default_false, mask=_BooleanValidator.default_mask, write_returns_value=False, - label=None, description=None): + label=None, description=None, device_kind=None): rw = _FeatureRW(feature, read_function_id, write_function_id) validator = _BooleanValidator(true_value=true_value, false_value=false_value, mask=mask, write_returns_value=write_returns_value) - return _Setting(name, rw, validator, label=label, description=description) + return _Setting(name, rw, validator, label=label, description=description, device_kind=device_kind)