device: improve device features handling
This commit is contained in:
parent
74304a98c7
commit
4459ea5342
|
@ -232,145 +232,87 @@ class FeatureCallError(_KwException):
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class FeaturesArray:
|
class FeaturesArray(dict):
|
||||||
"""A sequence of features supported by a HID++ 2.0 device."""
|
|
||||||
__slots__ = ('supported', 'device', 'features', 'non_features')
|
|
||||||
assert FEATURE.ROOT == 0x0000
|
|
||||||
|
|
||||||
def __init__(self, device):
|
def __init__(self, device):
|
||||||
assert device is not None
|
assert device is not None
|
||||||
self.device = device
|
|
||||||
self.supported = True
|
self.supported = True
|
||||||
self.features = None
|
self.device = device
|
||||||
self.non_features = set()
|
self.inverse = {}
|
||||||
|
self.count = 0
|
||||||
def __del__(self):
|
|
||||||
self.supported = False
|
|
||||||
self.device = None
|
|
||||||
self.features = None
|
|
||||||
|
|
||||||
def _check(self):
|
def _check(self):
|
||||||
# print (self.device, "check", self.supported, self.features, self.device.protocol)
|
if self.supported is False or not self.device.online:
|
||||||
if self.supported:
|
return False
|
||||||
assert self.device is not None
|
if self.device.protocol and self.device.protocol < 2.0:
|
||||||
if self.features is not None:
|
self.supported = False
|
||||||
return True
|
return False
|
||||||
|
if self.count > 0:
|
||||||
if not self.device.online:
|
return True
|
||||||
# device is not connected right now, will have to try later
|
reply = self.device.request(0x0000, _pack('!H', FEATURE.FEATURE_SET))
|
||||||
return False
|
if reply is not None:
|
||||||
|
fs_index = ord(reply[0:1])
|
||||||
# I _think_ this is universally true
|
if fs_index:
|
||||||
if self.device.protocol and self.device.protocol < 2.0:
|
count = self.device.request(fs_index << 8)
|
||||||
self.supported = False
|
if count is None:
|
||||||
self.device.features = None
|
_log.warn('FEATURE_SET found, but failed to read features count')
|
||||||
self.device = None
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
reply = self.device.request(0x0000, _pack('!H', FEATURE.FEATURE_SET))
|
|
||||||
if reply is None:
|
|
||||||
return False # device might not be active so don't assume unsupported
|
|
||||||
else:
|
|
||||||
fs_index = ord(reply[0:1])
|
|
||||||
if fs_index:
|
|
||||||
count = self.device.request(fs_index << 8)
|
|
||||||
if count is None:
|
|
||||||
_log.warn('FEATURE_SET found, but failed to read features count')
|
|
||||||
# most likely the device is unavailable
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
count = ord(count[:1])
|
|
||||||
assert count >= fs_index
|
|
||||||
self.features = [None] * (1 + count)
|
|
||||||
self.features[0] = FEATURE.ROOT
|
|
||||||
self.features[fs_index] = FEATURE.FEATURE_SET
|
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
self.supported = False
|
self.count = ord(count[:1])
|
||||||
|
self[FEATURE.ROOT] = 0
|
||||||
|
self[FEATURE.FEATURE_SET] = fs_index
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.supported = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_feature(self, index):
|
||||||
|
feature = self.inverse.get(index)
|
||||||
|
if feature is not None:
|
||||||
|
return feature
|
||||||
|
elif self._check():
|
||||||
|
feature = self.device.feature_request(FEATURE.FEATURE_SET, 0x10, index)
|
||||||
|
if feature:
|
||||||
|
feature = FEATURE[_unpack('!H', feature[:2])[0]]
|
||||||
|
self[feature] = index
|
||||||
|
return feature
|
||||||
|
|
||||||
|
def enumerate(self): # return all features and their index, ordered by index
|
||||||
|
if self._check():
|
||||||
|
for index in range(self.count):
|
||||||
|
feature = self.get_feature(index)
|
||||||
|
yield feature, index
|
||||||
|
|
||||||
__bool__ = __nonzero__ = _check
|
__bool__ = __nonzero__ = _check
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, feature):
|
||||||
if self._check():
|
index = super().get(feature)
|
||||||
if isinstance(index, int):
|
if index is not None:
|
||||||
if index < 0 or index >= len(self.features):
|
return index
|
||||||
raise IndexError(index)
|
elif self._check():
|
||||||
|
response = self.device.request(0x0000, _pack('!H', feature))
|
||||||
|
if response:
|
||||||
|
index = response[0]
|
||||||
|
self[feature] = index if index else False
|
||||||
|
return index if index else False
|
||||||
|
|
||||||
if self.features[index] is None:
|
def __setitem__(self, feature, index):
|
||||||
feature = self.device.feature_request(FEATURE.FEATURE_SET, 0x10, index)
|
if type(super().get(feature)) == int:
|
||||||
if feature:
|
self.inverse.pop(super().get(feature))
|
||||||
feature, = _unpack('!H', feature[:2])
|
super().__setitem__(feature, index)
|
||||||
self.features[index] = FEATURE[feature]
|
if type(index) == int:
|
||||||
|
self.inverse[index] = feature
|
||||||
|
|
||||||
return self.features[index]
|
def __delitem__(self, feature):
|
||||||
|
if type(super().get(feature)) == int:
|
||||||
|
self.inverse.pop(super().get(feature))
|
||||||
|
super().__delitem__(feature)
|
||||||
|
|
||||||
elif isinstance(index, slice):
|
def __contains__(self, feature): # is a feature present
|
||||||
indices = index.indices(len(self.features))
|
index = self.__getitem__(feature)
|
||||||
return [self.__getitem__(i) for i in range(*indices)]
|
return index is not None and index is not False
|
||||||
|
|
||||||
def __contains__(self, featureId):
|
|
||||||
"""Tests whether the list contains given Feature ID"""
|
|
||||||
if self._check():
|
|
||||||
ivalue = int(featureId)
|
|
||||||
if ivalue in self.non_features:
|
|
||||||
return False
|
|
||||||
|
|
||||||
may_have = False
|
|
||||||
for f in self.features:
|
|
||||||
if f is None:
|
|
||||||
may_have = True
|
|
||||||
elif ivalue == int(f):
|
|
||||||
return True
|
|
||||||
|
|
||||||
if may_have and self.device:
|
|
||||||
reply = self.device.request(0x0000, _pack('!H', ivalue))
|
|
||||||
if reply:
|
|
||||||
index = ord(reply[0:1])
|
|
||||||
if index:
|
|
||||||
self.features[index] = FEATURE[ivalue]
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
self.non_features.add(ivalue)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def index(self, featureId):
|
|
||||||
"""Gets the Feature Index for a given Feature ID"""
|
|
||||||
if self._check():
|
|
||||||
may_have = False
|
|
||||||
ivalue = int(featureId)
|
|
||||||
for index, f in enumerate(self.features):
|
|
||||||
if f is None:
|
|
||||||
may_have = True
|
|
||||||
elif ivalue == int(f):
|
|
||||||
return index
|
|
||||||
|
|
||||||
if may_have:
|
|
||||||
reply = self.device.request(0x0000, _pack('!H', ivalue))
|
|
||||||
if reply:
|
|
||||||
index = ord(reply[0:1])
|
|
||||||
self.features[index] = FEATURE[ivalue]
|
|
||||||
return index
|
|
||||||
|
|
||||||
raise ValueError('%r not in list' % featureId)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
if self._check():
|
|
||||||
yield FEATURE.ROOT
|
|
||||||
index = 1
|
|
||||||
last_index = len(self.features)
|
|
||||||
while index < last_index:
|
|
||||||
yield self.__getitem__(index)
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.features) if self._check() else 0
|
return self.count
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class ReprogrammableKey:
|
class ReprogrammableKey:
|
||||||
|
@ -1157,7 +1099,7 @@ class Gestures:
|
||||||
def feature_request(device, feature, function=0x00, *params, no_reply=False):
|
def feature_request(device, feature, function=0x00, *params, no_reply=False):
|
||||||
if device.online and device.features:
|
if device.online and device.features:
|
||||||
if feature in device.features:
|
if feature in device.features:
|
||||||
feature_index = device.features.index(int(feature))
|
feature_index = device.features[feature]
|
||||||
return device.request((feature_index << 8) + (function & 0xFF), *params, no_reply=no_reply)
|
return device.request((feature_index << 8) + (function & 0xFF), *params, no_reply=no_reply)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -135,8 +135,7 @@ def _print_device(dev, num=None):
|
||||||
print(' Supports %d HID++ 2.0 features:' % len(dev.features))
|
print(' Supports %d HID++ 2.0 features:' % len(dev.features))
|
||||||
dev_settings = []
|
dev_settings = []
|
||||||
_settings_templates.check_feature_settings(dev, dev_settings)
|
_settings_templates.check_feature_settings(dev, dev_settings)
|
||||||
for index, feature in enumerate(dev.features):
|
for feature, index in dev.features.enumerate():
|
||||||
feature = dev.features[index]
|
|
||||||
flags = dev.request(0x0000, feature.bytes(2))
|
flags = dev.request(0x0000, feature.bytes(2))
|
||||||
flags = 0 if flags is None else ord(flags[1:2])
|
flags = 0 if flags is None else ord(flags[1:2])
|
||||||
flags = _hidpp20.FEATURE_FLAG.flag_names(flags)
|
flags = _hidpp20.FEATURE_FLAG.flag_names(flags)
|
||||||
|
|
Loading…
Reference in New Issue