device: improve device features handling
This commit is contained in:
parent
74304a98c7
commit
4459ea5342
|
@ -232,145 +232,87 @@ class FeatureCallError(_KwException):
|
|||
#
|
||||
|
||||
|
||||
class FeaturesArray:
|
||||
"""A sequence of features supported by a HID++ 2.0 device."""
|
||||
__slots__ = ('supported', 'device', 'features', 'non_features')
|
||||
assert FEATURE.ROOT == 0x0000
|
||||
|
||||
class FeaturesArray(dict):
|
||||
def __init__(self, device):
|
||||
assert device is not None
|
||||
self.device = device
|
||||
self.supported = True
|
||||
self.features = None
|
||||
self.non_features = set()
|
||||
|
||||
def __del__(self):
|
||||
self.supported = False
|
||||
self.device = None
|
||||
self.features = None
|
||||
self.device = device
|
||||
self.inverse = {}
|
||||
self.count = 0
|
||||
|
||||
def _check(self):
|
||||
# print (self.device, "check", self.supported, self.features, self.device.protocol)
|
||||
if self.supported:
|
||||
assert self.device is not None
|
||||
if self.features is not None:
|
||||
return True
|
||||
|
||||
if not self.device.online:
|
||||
# device is not connected right now, will have to try later
|
||||
if self.supported is False or not self.device.online:
|
||||
return False
|
||||
|
||||
# I _think_ this is universally true
|
||||
if self.device.protocol and self.device.protocol < 2.0:
|
||||
self.supported = False
|
||||
self.device.features = None
|
||||
self.device = None
|
||||
return False
|
||||
|
||||
if self.count > 0:
|
||||
return True
|
||||
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:
|
||||
if reply is not None:
|
||||
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
|
||||
self.count = ord(count[:1])
|
||||
self[FEATURE.ROOT] = 0
|
||||
self[FEATURE.FEATURE_SET] = fs_index
|
||||
return True
|
||||
else:
|
||||
self.supported = 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
|
||||
|
||||
def __getitem__(self, index):
|
||||
if self._check():
|
||||
if isinstance(index, int):
|
||||
if index < 0 or index >= len(self.features):
|
||||
raise IndexError(index)
|
||||
|
||||
if self.features[index] is None:
|
||||
feature = self.device.feature_request(FEATURE.FEATURE_SET, 0x10, index)
|
||||
if feature:
|
||||
feature, = _unpack('!H', feature[:2])
|
||||
self.features[index] = FEATURE[feature]
|
||||
|
||||
return self.features[index]
|
||||
|
||||
elif isinstance(index, slice):
|
||||
indices = index.indices(len(self.features))
|
||||
return [self.__getitem__(i) for i in range(*indices)]
|
||||
|
||||
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):
|
||||
def __getitem__(self, feature):
|
||||
index = super().get(feature)
|
||||
if index is not None:
|
||||
return 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 may_have:
|
||||
reply = self.device.request(0x0000, _pack('!H', ivalue))
|
||||
if reply:
|
||||
index = ord(reply[0:1])
|
||||
self.features[index] = FEATURE[ivalue]
|
||||
return index
|
||||
def __setitem__(self, feature, index):
|
||||
if type(super().get(feature)) == int:
|
||||
self.inverse.pop(super().get(feature))
|
||||
super().__setitem__(feature, index)
|
||||
if type(index) == int:
|
||||
self.inverse[index] = feature
|
||||
|
||||
raise ValueError('%r not in list' % featureId)
|
||||
def __delitem__(self, feature):
|
||||
if type(super().get(feature)) == int:
|
||||
self.inverse.pop(super().get(feature))
|
||||
super().__delitem__(feature)
|
||||
|
||||
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 __contains__(self, feature): # is a feature present
|
||||
index = self.__getitem__(feature)
|
||||
return index is not None and index is not False
|
||||
|
||||
def __len__(self):
|
||||
return len(self.features) if self._check() else 0
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
return self.count
|
||||
|
||||
|
||||
class ReprogrammableKey:
|
||||
|
@ -1157,7 +1099,7 @@ class Gestures:
|
|||
def feature_request(device, feature, function=0x00, *params, no_reply=False):
|
||||
if device.online and 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)
|
||||
|
||||
|
||||
|
|
|
@ -135,8 +135,7 @@ def _print_device(dev, num=None):
|
|||
print(' Supports %d HID++ 2.0 features:' % len(dev.features))
|
||||
dev_settings = []
|
||||
_settings_templates.check_feature_settings(dev, dev_settings)
|
||||
for index, feature in enumerate(dev.features):
|
||||
feature = dev.features[index]
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue