named ints act like proper sequences now
This commit is contained in:
parent
f0007d0a13
commit
9066003240
|
@ -8,11 +8,10 @@ from struct import pack as _pack
|
|||
|
||||
class NamedInt(int):
|
||||
"""An integer with an attached name."""
|
||||
# __slots__ = ['name']
|
||||
|
||||
def __new__(cls, value, name):
|
||||
obj = int.__new__(cls, value)
|
||||
obj.name = name
|
||||
obj.name = str(name)
|
||||
return obj
|
||||
|
||||
def bytes(self, count=2):
|
||||
|
@ -22,6 +21,17 @@ class NamedInt(int):
|
|||
|
||||
return _pack('!L', value)[-count:]
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
if int(self) == int(other):
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return self.name.lower() == str(other).lower()
|
||||
|
||||
def __cmp__(self, other):
|
||||
return int(self) - int(other)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
@ -30,30 +40,50 @@ class NamedInt(int):
|
|||
|
||||
|
||||
class NamedInts(object):
|
||||
__slots__ = ['__dict__', '_values', '_indexed', '_fallback']
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
values = dict((k, NamedInt(v, k if k == k.upper() else k.replace('__', '/').replace('_', ' '))) for (k, v) in kwargs.items())
|
||||
self.__dict__.update(values)
|
||||
self._indexed = dict((int(v), v) for v in values.values())
|
||||
values = dict((k, NamedInt(v, k.lstrip('_') if k == k.upper() else
|
||||
k.replace('__', '/').replace('_', ' '))) for (k, v) in kwargs.items())
|
||||
self.__dict__ = values
|
||||
self._values = sorted(list(values.values()))
|
||||
self._indexed = dict((int(v), v) for v in self._values)
|
||||
self._fallback = None
|
||||
|
||||
def __getitem__(self, index):
|
||||
if index in self._indexed:
|
||||
return self._indexed[index]
|
||||
|
||||
if self._fallback:
|
||||
value = NamedInt(index, self._fallback(index))
|
||||
self._indexed[index] = value
|
||||
return value
|
||||
|
||||
def __contains__(self, value):
|
||||
return int(value) in self._indexed
|
||||
|
||||
def __len__(self):
|
||||
return len(self.values)
|
||||
|
||||
def flag_names(self, value):
|
||||
return ', '.join(str(self._indexed[k]) for k in self._indexed if k & value == k)
|
||||
|
||||
def __getitem__(self, index):
|
||||
if type(index) == int:
|
||||
if index in self._indexed:
|
||||
return self._indexed[index]
|
||||
|
||||
if self._fallback:
|
||||
value = NamedInt(index, self._fallback(index))
|
||||
self._indexed[index] = value
|
||||
self._values = sorted(self._values + [value])
|
||||
return value
|
||||
|
||||
elif type(index) == slice:
|
||||
return self._values[index]
|
||||
|
||||
else:
|
||||
if index in self._values:
|
||||
index = self._values.index(index)
|
||||
return self._values[index]
|
||||
|
||||
def __contains__(self, value):
|
||||
return value in self._values
|
||||
|
||||
def __iter__(self):
|
||||
return iter(sorted(self._values))
|
||||
|
||||
def __len__(self):
|
||||
return len(self._values)
|
||||
|
||||
def __repr__(self):
|
||||
return 'NamedInts(%s)' % ', '.join(repr(v) for v in self._values)
|
||||
|
||||
|
||||
def strhex(x):
|
||||
return _hexlify(x).decode('ascii').upper()
|
||||
|
|
|
@ -57,10 +57,6 @@ PAIRING_ERRORS = _NamedInts(
|
|||
too_many_devices=0x03,
|
||||
sequence_timeout=0x06)
|
||||
|
||||
REGISTERS = _NamedInts(
|
||||
battery=0x0D,
|
||||
dpi=0x63,
|
||||
leds=0x51)
|
||||
|
||||
#
|
||||
# functions
|
||||
|
|
|
@ -31,7 +31,7 @@ FEATURE = _NamedInts(
|
|||
BATTERY=0x1000,
|
||||
REPROGRAMMABLE_KEYS=0x1B00,
|
||||
WIRELESS=0x1D4B,
|
||||
FN_TOGGLE=0x40A0,
|
||||
FN_STATUS=0x40A0,
|
||||
SOLAR_CHARGE=0x4301,
|
||||
TOUCH_MOUSE=0x6110)
|
||||
FEATURE._fallback = lambda x: 'unknown:%04X' % x
|
||||
|
@ -80,7 +80,7 @@ KEY = _NamedInts(
|
|||
Calculator=0x000A,
|
||||
Mail=0x000E,
|
||||
Home=0x001A,
|
||||
Tools=0x001D,
|
||||
Music=0x001D,
|
||||
Search=0x0029,
|
||||
Sleep=0x002F)
|
||||
KEY._fallback = lambda x: 'unknown:%04X' % x
|
||||
|
|
|
@ -118,7 +118,7 @@ class PairedDevice(object):
|
|||
p = self.protocol
|
||||
if p >= 2.0:
|
||||
self._firmware = _hidpp20.get_firmware(self)
|
||||
elif p >= 1.0:
|
||||
if self._firmware is None and p == 1.0:
|
||||
self._firmware = _hidpp10.get_firmware(self)
|
||||
return self._firmware or ()
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ class DeviceStatus(dict):
|
|||
return ', '.join(t)
|
||||
|
||||
def __bool__(self):
|
||||
return self.updated and self._active
|
||||
return bool(self._active)
|
||||
__nonzero__ = __bool__
|
||||
|
||||
def _changed(self, active=True, alert=ALERT.NONE, reason=None, timestamp=None):
|
||||
|
@ -131,13 +131,20 @@ class DeviceStatus(dict):
|
|||
d.protocol, d.serial, d.firmware
|
||||
|
||||
if BATTERY_LEVEL not in self:
|
||||
if d.protocol >= 2.0:
|
||||
battery = _hidpp10.get_battery(d)
|
||||
if battery is None and d.protocol >= 2.0:
|
||||
battery = _hidpp20.get_battery(d)
|
||||
else:
|
||||
battery = _hidpp10.get_battery(d)
|
||||
|
||||
# if battery is None and _hidpp20.FEATURE.SOLAR_CHARGE in d.features:
|
||||
# d.feature_request(_hidpp20.FEATURE.SOLAR_CHARGE, 0x00, 1, 1)
|
||||
# return
|
||||
|
||||
if battery:
|
||||
self[BATTERY_LEVEL], self[BATTERY_STATUS] = battery
|
||||
self._changed(timestamp=timestamp)
|
||||
elif BATTERY_STATUS in self:
|
||||
self[BATTERY_STATUS] = None
|
||||
self._changed(timestamp=timestamp)
|
||||
|
||||
elif len(self) > 0 and timestamp - self.updated > _STATUS_TIMEOUT:
|
||||
# if the device has been inactive for too long, clear out any known
|
||||
|
@ -191,7 +198,7 @@ class DeviceStatus(dict):
|
|||
if event.sub_id >= 0x80:
|
||||
# this can't possibly be an event, can it?
|
||||
if _log.isEnabledFor(_DEBUG):
|
||||
_log.debug("ignoring non-event %s", event)
|
||||
_log.debug("ignoring %s (not an event)", event)
|
||||
return False
|
||||
|
||||
if event.sub_id >= 0x40:
|
||||
|
|
Loading…
Reference in New Issue