receiver: add setting for MULTIPLATFORM and DUALPLATFORM feature
This commit is contained in:
parent
1dc59fd374
commit
c9c472e391
|
@ -75,8 +75,8 @@ Feature | ID | Status | Notes
|
|||
`KEYBOARD_LAYOUT` | `0x4520` | :x: | read only
|
||||
`KEYBOARD_DISABLE_KEYS` | `0x4521` | :heavy_check_mark: | `_feature_disable_keyboard_keys`
|
||||
`KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | :x: |
|
||||
`DUALPLATFORM` | `0x4530` | :x: | :wrench:
|
||||
`MULTIPLATFORM` | `0x4531` | :x: | :wrench:
|
||||
`DUALPLATFORM` | `0x4530` | :heavy_check_mark: | `_feature_dualplatform`, untested
|
||||
`MULTIPLATFORM` | `0x4531` | :heavy_check_mark: | `_feature_multiplatform`
|
||||
`KEYBOARD_LAYOUT_2` | `0x4540` | :x: | read only
|
||||
`CROWN` | `0x4600` | :x: |
|
||||
`TOUCHPAD_FW_ITEMS` | `0x6010` | :x: |
|
||||
|
|
|
@ -45,7 +45,7 @@ class Setting(object):
|
|||
Needs to be instantiated for each specific device."""
|
||||
__slots__ = ('name', 'label', 'description', 'kind', 'device_kind', 'feature', '_rw', '_validator', '_device', '_value')
|
||||
|
||||
def __init__(self, name, rw, validator, kind=None, label=None, description=None, device_kind=None, feature=None):
|
||||
def __init__(self, name, rw, validator, kind=None, label=None, description=None, device_kind=None, feature=None, **kwargs):
|
||||
assert name
|
||||
self.name = name
|
||||
self.label = label or name
|
||||
|
@ -434,7 +434,7 @@ class FeatureRW(object):
|
|||
default_read_fnid = 0x00
|
||||
default_write_fnid = 0x10
|
||||
|
||||
def __init__(self, feature, read_fnid=default_read_fnid, write_fnid=default_write_fnid):
|
||||
def __init__(self, feature, read_fnid=default_read_fnid, write_fnid=default_write_fnid, **kwargs):
|
||||
assert isinstance(feature, _NamedInt)
|
||||
self.feature = feature
|
||||
self.read_fnid = read_fnid
|
||||
|
@ -453,23 +453,30 @@ class FeatureRWMap(FeatureRW):
|
|||
kind = _NamedInt(0x02, 'feature')
|
||||
default_read_fnid = 0x00
|
||||
default_write_fnid = 0x10
|
||||
default_key_bytes = 1
|
||||
default_key_bytes_count = 1
|
||||
|
||||
def __init__(self, feature, read_fnid=default_read_fnid, write_fnid=default_write_fnid, key_bytes=default_key_bytes):
|
||||
def __init__(
|
||||
self,
|
||||
feature,
|
||||
read_fnid=default_read_fnid,
|
||||
write_fnid=default_write_fnid,
|
||||
key_bytes_count=default_key_bytes_count,
|
||||
**kwargs
|
||||
):
|
||||
assert isinstance(feature, _NamedInt)
|
||||
self.feature = feature
|
||||
self.read_fnid = read_fnid
|
||||
self.write_fnid = write_fnid
|
||||
self.key_bytes = key_bytes
|
||||
self.key_bytes_count = key_bytes_count
|
||||
|
||||
def read(self, device, key):
|
||||
assert self.feature is not None
|
||||
key_bytes = _int2bytes(key, self.key_bytes)
|
||||
key_bytes = _int2bytes(key, self.key_bytes_count)
|
||||
return device.feature_request(self.feature, self.read_fnid, key_bytes)
|
||||
|
||||
def write(self, device, key, data_bytes):
|
||||
assert self.feature is not None
|
||||
key_bytes = _int2bytes(key, self.key_bytes)
|
||||
key_bytes = _int2bytes(key, self.key_bytes_count)
|
||||
return device.feature_request(self.feature, self.write_fnid, key_bytes, data_bytes)
|
||||
|
||||
|
||||
|
@ -488,7 +495,7 @@ class BooleanValidator(object):
|
|||
# mask specifies all the affected bits in the value
|
||||
default_mask = 0xFF
|
||||
|
||||
def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask):
|
||||
def __init__(self, true_value=default_true, false_value=default_false, mask=default_mask, **kwargs):
|
||||
if isinstance(true_value, int):
|
||||
assert isinstance(false_value, int)
|
||||
if mask is None:
|
||||
|
@ -593,7 +600,7 @@ class BitFieldValidator(object):
|
|||
|
||||
kind = KIND.multiple_toggle
|
||||
|
||||
def __init__(self, options, byte_count=None):
|
||||
def __init__(self, options, byte_count=None, **kwargs):
|
||||
assert (isinstance(options, list))
|
||||
self.options = options
|
||||
self.byte_count = (max(x.bit_length() for x in options) + 7) // 8
|
||||
|
@ -621,14 +628,12 @@ class BitFieldValidator(object):
|
|||
|
||||
|
||||
class ChoicesValidator(object):
|
||||
__slots__ = ('choices', 'flag', '_bytes_count', 'needs_current_value')
|
||||
|
||||
kind = KIND.choice
|
||||
"""Translates between NamedInts and a byte sequence.
|
||||
:param choices: a list of NamedInts
|
||||
:param bytes_count: the size of the derived byte sequence. If None, it
|
||||
will be calculated from the choices."""
|
||||
def __init__(self, choices, bytes_count=None):
|
||||
def __init__(self, choices, bytes_count=None, read_skip_bytes_count=None, write_prefix_bytes=b'', **_ignore):
|
||||
assert choices is not None
|
||||
assert isinstance(choices, _NamedInts)
|
||||
assert len(choices) > 2
|
||||
|
@ -641,9 +646,13 @@ class ChoicesValidator(object):
|
|||
assert self._bytes_count <= bytes_count
|
||||
self._bytes_count = bytes_count
|
||||
assert self._bytes_count < 8
|
||||
self._read_skip_bytes_count = read_skip_bytes_count if read_skip_bytes_count else 0
|
||||
self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b''
|
||||
assert self._bytes_count + self._read_skip_bytes_count <= 14
|
||||
assert self._bytes_count + len(self._write_prefix_bytes) <= 14
|
||||
|
||||
def validate_read(self, reply_bytes):
|
||||
reply_value = _bytes2int(reply_bytes[:self._bytes_count])
|
||||
reply_value = _bytes2int(reply_bytes[self._read_skip_bytes_count:self._read_skip_bytes_count + self._bytes_count])
|
||||
valid_value = self.choices[reply_value]
|
||||
assert valid_value is not None, '%s: failed to validate read value %02X' % (self.__class__.__name__, reply_value)
|
||||
return valid_value
|
||||
|
@ -664,13 +673,22 @@ class ChoicesValidator(object):
|
|||
if choice is None:
|
||||
raise ValueError('invalid choice %r' % new_value)
|
||||
assert isinstance(choice, _NamedInt)
|
||||
return choice.bytes(self._bytes_count)
|
||||
return self._write_prefix_bytes + choice.bytes(self._bytes_count)
|
||||
|
||||
|
||||
class ChoicesMapValidator(ChoicesValidator):
|
||||
kind = KIND.map_choice
|
||||
|
||||
def __init__(self, choices_map, key_bytes_count=None, skip_bytes_count=None, value_bytes_count=None, extra_default=None):
|
||||
def __init__(
|
||||
self,
|
||||
choices_map,
|
||||
key_bytes_count=None,
|
||||
bytes_count=None,
|
||||
read_skip_bytes_count=0,
|
||||
write_prefix_bytes=b'',
|
||||
extra_default=None,
|
||||
**kwargs
|
||||
):
|
||||
assert choices_map is not None
|
||||
assert isinstance(choices_map, dict)
|
||||
max_key_bits = 0
|
||||
|
@ -682,24 +700,25 @@ class ChoicesMapValidator(ChoicesValidator):
|
|||
for key_value in choices:
|
||||
assert isinstance(key_value, _NamedInt)
|
||||
max_value_bits = max(max_value_bits, key_value.bit_length())
|
||||
self.choices = choices_map
|
||||
self.needs_current_value = False
|
||||
self.extra_default = extra_default
|
||||
|
||||
self._key_bytes_count = (max_key_bits + 7) // 8
|
||||
if key_bytes_count:
|
||||
assert self._key_bytes_count <= key_bytes_count
|
||||
self._key_bytes_count = key_bytes_count
|
||||
self._value_bytes_count = (max_value_bits + 7) // 8
|
||||
if value_bytes_count:
|
||||
assert self._value_bytes_count <= value_bytes_count
|
||||
self._value_bytes_count = value_bytes_count
|
||||
self._skip_bytes_count = skip_bytes_count if skip_bytes_count is not None else 0
|
||||
self._bytes_count = self._key_bytes_count + self._skip_bytes_count + self._value_bytes_count
|
||||
self._bytes_count = (max_value_bits + 7) // 8
|
||||
if bytes_count:
|
||||
assert self._bytes_count <= bytes_count
|
||||
self._bytes_count = bytes_count
|
||||
self.choices = choices_map
|
||||
self.needs_current_value = False
|
||||
self.extra_default = extra_default
|
||||
self._read_skip_bytes_count = read_skip_bytes_count if read_skip_bytes_count else 0
|
||||
self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b''
|
||||
assert self._bytes_count + self._read_skip_bytes_count + self._key_bytes_count <= 14
|
||||
assert self._bytes_count + len(self._write_prefix_bytes) + self._key_bytes_count <= 14
|
||||
|
||||
def validate_read(self, reply_bytes, key):
|
||||
start = self._key_bytes_count + self._skip_bytes_count
|
||||
end = start + self._value_bytes_count
|
||||
start = self._key_bytes_count + self._read_skip_bytes_count
|
||||
end = start + self._bytes_count
|
||||
reply_value = _bytes2int(reply_bytes[start:end])
|
||||
# reprogrammable keys starts out as 0, which is not a choice, so don't use assert here
|
||||
if self.extra_default is not None and self.extra_default == reply_value:
|
||||
|
@ -712,7 +731,7 @@ class ChoicesMapValidator(ChoicesValidator):
|
|||
choices = self.choices[key]
|
||||
if new_value not in choices and new_value != self.extra_default:
|
||||
raise ValueError('invalid choice %r' % new_value)
|
||||
return _int2bytes(new_value, self._skip_bytes_count + self._value_bytes_count)
|
||||
return self._write_prefix_bytes + new_value.to_bytes(self._bytes_count, 'big')
|
||||
|
||||
|
||||
class RangeValidator(object):
|
||||
|
@ -724,7 +743,7 @@ class RangeValidator(object):
|
|||
:param max_value: maximum accepted value (inclusive)
|
||||
:param bytes_count: the size of the derived byte sequence. If None, it
|
||||
will be calculated from the range."""
|
||||
def __init__(self, min_value, max_value, bytes_count=None):
|
||||
def __init__(self, min_value, max_value, bytes_count=None, **kwargs):
|
||||
assert max_value > min_value
|
||||
self.min_value = min_value
|
||||
self.max_value = max_value
|
||||
|
|
|
@ -82,8 +82,8 @@ def register_choices(name, register, choices, kind=_KIND.choice, label=None, des
|
|||
def feature_toggle(
|
||||
name,
|
||||
feature,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
read_fnid=_FeatureRW.default_read_fnid,
|
||||
write_fnid=_FeatureRW.default_write_fnid,
|
||||
true_value=_BooleanV.default_true,
|
||||
false_value=_BooleanV.default_false,
|
||||
mask=_BooleanV.default_mask,
|
||||
|
@ -92,7 +92,7 @@ def feature_toggle(
|
|||
device_kind=None
|
||||
):
|
||||
validator = _BooleanV(true_value=true_value, false_value=false_value, mask=mask)
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
rw = _FeatureRW(feature, read_fnid=read_fnid, write_fnid=write_fnid)
|
||||
return _Setting(name, rw, validator, feature=feature, label=label, description=description, device_kind=device_kind)
|
||||
|
||||
|
||||
|
@ -100,15 +100,15 @@ def feature_bitfield_toggle(
|
|||
name,
|
||||
feature,
|
||||
options,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
read_fnid=_FeatureRW.default_read_fnid,
|
||||
write_fnid=_FeatureRW.default_write_fnid,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
assert options
|
||||
validator = _BitFieldV(options)
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
rw = _FeatureRW(feature, read_fnid=read_fnid, write_fnid=write_fnid)
|
||||
return _BitFieldSetting(
|
||||
name, rw, validator, feature=feature, label=label, description=description, device_kind=device_kind
|
||||
)
|
||||
|
@ -118,8 +118,8 @@ def feature_bitfield_toggle_dynamic(
|
|||
name,
|
||||
feature,
|
||||
options_callback,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
read_fnid=_FeatureRW.default_read_fnid,
|
||||
write_fnid=_FeatureRW.default_write_fnid,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
|
@ -130,8 +130,8 @@ def feature_bitfield_toggle_dynamic(
|
|||
name,
|
||||
feature,
|
||||
options,
|
||||
read_function_id=read_function_id,
|
||||
write_function_id=write_function_id,
|
||||
read_fnid=read_fnid,
|
||||
write_fnid=write_fnid,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
|
@ -142,51 +142,21 @@ def feature_bitfield_toggle_dynamic(
|
|||
return instantiate
|
||||
|
||||
|
||||
def feature_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
def feature_choices(name, feature, choices, **kwargs):
|
||||
assert choices
|
||||
validator = _ChoicesV(choices, bytes_count=bytes_count)
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
return _Setting(
|
||||
name, rw, validator, feature=feature, kind=_KIND.choice, label=label, description=description, device_kind=device_kind
|
||||
)
|
||||
validator = _ChoicesV(choices, **kwargs)
|
||||
rw = _FeatureRW(feature, **kwargs)
|
||||
return _Setting(name, rw, validator, kind=_KIND.choice, **kwargs)
|
||||
|
||||
|
||||
def feature_choices_dynamic(
|
||||
name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None
|
||||
):
|
||||
def feature_choices_dynamic(name, feature, choices_callback, **kwargs):
|
||||
# Proxy that obtains choices dynamically from a device
|
||||
def instantiate(device):
|
||||
# Obtain choices for this feature
|
||||
choices = choices_callback(device)
|
||||
setting = feature_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
bytes_count=bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
)
|
||||
if not choices: # no choices, so don't create a setting
|
||||
return None
|
||||
setting = feature_choices(name, feature, choices, **kwargs)
|
||||
return setting(device)
|
||||
|
||||
instantiate._rw_kind = _FeatureRW.kind
|
||||
|
@ -195,75 +165,20 @@ def feature_choices_dynamic(
|
|||
|
||||
# maintain a mapping from keys (NamedInts) to one of a list of choices (NamedInts), default is first one
|
||||
# the setting is stored as a JSON-compatible object mapping the key int (as a string) to the choice int
|
||||
# extra_default is an extra value that comes from the device that also means the default
|
||||
def feature_map_choices(
|
||||
name,
|
||||
feature,
|
||||
choicesmap,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None
|
||||
):
|
||||
def feature_map_choices(name, feature, choicesmap, **kwargs):
|
||||
assert choicesmap
|
||||
validator = _ChoicesMapV(
|
||||
choicesmap,
|
||||
key_bytes_count=key_bytes_count,
|
||||
skip_bytes_count=skip_bytes_count,
|
||||
value_bytes_count=value_bytes_count,
|
||||
extra_default=extra_default
|
||||
)
|
||||
rw = _FeatureRWMap(feature, read_function_id, write_function_id, key_bytes=key_bytes_count)
|
||||
return _Settings(
|
||||
name,
|
||||
rw,
|
||||
validator,
|
||||
feature=feature,
|
||||
kind=_KIND.map_choice,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind
|
||||
)
|
||||
validator = _ChoicesMapV(choicesmap, **kwargs)
|
||||
rw = _FeatureRWMap(feature, **kwargs)
|
||||
return _Settings(name, rw, validator, kind=_KIND.map_choice, **kwargs)
|
||||
|
||||
|
||||
def feature_map_choices_dynamic(
|
||||
name,
|
||||
feature,
|
||||
choices_callback,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=None,
|
||||
skip_bytes_count=None,
|
||||
value_bytes_count=None,
|
||||
label=None,
|
||||
description=None,
|
||||
device_kind=None,
|
||||
extra_default=None
|
||||
):
|
||||
def feature_map_choices_dynamic(name, feature, choices_callback, **kwargs):
|
||||
# Proxy that obtains choices dynamically from a device
|
||||
def instantiate(device):
|
||||
choices = choices_callback(device)
|
||||
if not choices: # no choices, so don't create a Setting
|
||||
return None
|
||||
setting = feature_map_choices(
|
||||
name,
|
||||
feature,
|
||||
choices,
|
||||
read_function_id,
|
||||
write_function_id,
|
||||
key_bytes_count=key_bytes_count,
|
||||
skip_bytes_count=skip_bytes_count,
|
||||
value_bytes_count=value_bytes_count,
|
||||
label=label,
|
||||
description=description,
|
||||
device_kind=device_kind,
|
||||
extra_default=extra_default
|
||||
)
|
||||
setting = feature_map_choices(name, feature, choices, **kwargs)
|
||||
return setting(device)
|
||||
|
||||
instantiate._rw_kind = _FeatureRWMap.kind
|
||||
|
@ -275,8 +190,8 @@ def feature_range(
|
|||
feature,
|
||||
min_value,
|
||||
max_value,
|
||||
read_function_id=_FeatureRW.default_read_fnid,
|
||||
write_function_id=_FeatureRW.default_write_fnid,
|
||||
read_fnid=_FeatureRW.default_read_fnid,
|
||||
write_fnid=_FeatureRW.default_write_fnid,
|
||||
rw=None,
|
||||
bytes_count=None,
|
||||
label=None,
|
||||
|
@ -285,7 +200,7 @@ def feature_range(
|
|||
):
|
||||
validator = _RangeV(min_value, max_value, bytes_count=bytes_count)
|
||||
if rw is None:
|
||||
rw = _FeatureRW(feature, read_function_id, write_function_id)
|
||||
rw = _FeatureRW(feature, read_fnid=read_fnid, write_fnid=write_fnid)
|
||||
return _Setting(
|
||||
name, rw, validator, feature=feature, kind=_KIND.range, label=label, description=description, device_kind=device_kind
|
||||
)
|
||||
|
@ -342,10 +257,22 @@ _REPROGRAMMABLE_KEYS = (
|
|||
_('Changing important actions (such as for the left mouse button) can result in an unusable system.')
|
||||
)
|
||||
_DISABLE_KEYS = ('disable-keyboard-keys', _('Disable keys'), _('Disable specific keyboard keys.'))
|
||||
_PLATFORM = ('multiplatform', _('Set OS'), _('Change keys to match OS.'))
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
# Keyword arguments for setting template functions:
|
||||
# label, description - label and tooltip to be shown in GUI
|
||||
# device_kind - the kinds of devices that setting is suitable for (NOT CURRENTLY USED)
|
||||
# read_fnid, write_fnid - default 0x00 and 0x10 function numbers (times 16) to read and write setting
|
||||
# bytes_count - default 1 - number of bytes for the data (ignoring the key)
|
||||
# only for boolean settings
|
||||
# true_value, false_value, mask - integer or byte strings for boolean settings
|
||||
# only for map choices
|
||||
# key_bytes_count - default 1 - number of bytes in the key
|
||||
# extra_default - extra value that cannot be set but means same as default value
|
||||
# only for choices and map choices
|
||||
# read_skip_bytes_count - default 0 - number of bytes to ignore before the data when reading
|
||||
# write_prefix_bytes - default None - bytes to put before the data writing
|
||||
|
||||
|
||||
def _register_hand_detection(
|
||||
|
@ -463,8 +390,8 @@ def _feature_hires_smooth_invert():
|
|||
return feature_toggle(
|
||||
_HIRES_INV[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
read_fnid=0x10,
|
||||
write_fnid=0x20,
|
||||
true_value=0x04,
|
||||
mask=0x04,
|
||||
label=_HIRES_INV[1],
|
||||
|
@ -477,8 +404,8 @@ def _feature_hires_smooth_resolution():
|
|||
return feature_toggle(
|
||||
_HIRES_RES[0],
|
||||
_F.HIRES_WHEEL,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
read_fnid=0x10,
|
||||
write_fnid=0x20,
|
||||
true_value=0x02,
|
||||
mask=0x02,
|
||||
label=_HIRES_RES[1],
|
||||
|
@ -562,8 +489,8 @@ def _feature_adjustable_dpi():
|
|||
_DPI[0],
|
||||
_F.ADJUSTABLE_DPI,
|
||||
_feature_adjustable_dpi_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
read_fnid=0x20,
|
||||
write_fnid=0x30,
|
||||
bytes_count=3,
|
||||
label=_DPI[1],
|
||||
description=_DPI[2],
|
||||
|
@ -579,8 +506,8 @@ def _feature_pointer_speed():
|
|||
_F.POINTER_SPEED,
|
||||
0x002e,
|
||||
0x01ff,
|
||||
read_function_id=0x0,
|
||||
write_function_id=0x10,
|
||||
read_fnid=0x0,
|
||||
write_fnid=0x10,
|
||||
bytes_count=2,
|
||||
label=_POINTER_SPEED[1],
|
||||
description=_POINTER_SPEED[2],
|
||||
|
@ -624,15 +551,16 @@ def _feature_reprogrammable_keys():
|
|||
_REPROGRAMMABLE_KEYS[0],
|
||||
_F.REPROG_CONTROLS_V4,
|
||||
_feature_reprogrammable_keys_choices,
|
||||
read_function_id=0x20,
|
||||
write_function_id=0x30,
|
||||
read_fnid=0x20,
|
||||
write_fnid=0x30,
|
||||
key_bytes_count=2,
|
||||
skip_bytes_count=1,
|
||||
value_bytes_count=2,
|
||||
bytes_count=2,
|
||||
read_skip_bytes_count=1,
|
||||
write_prefix_bytes=b'\x00',
|
||||
extra_default=0,
|
||||
label=_REPROGRAMMABLE_KEYS[1],
|
||||
description=_REPROGRAMMABLE_KEYS[2],
|
||||
device_kind=(_DK.keyboard, ),
|
||||
extra_default=0
|
||||
)
|
||||
|
||||
|
||||
|
@ -647,14 +575,83 @@ def _feature_disable_keyboard_keys():
|
|||
_DISABLE_KEYS[0],
|
||||
_F.KEYBOARD_DISABLE_KEYS,
|
||||
_feature_disable_keyboard_keys_key_list,
|
||||
read_function_id=0x10,
|
||||
write_function_id=0x20,
|
||||
read_fnid=0x10,
|
||||
write_fnid=0x20,
|
||||
label=_DISABLE_KEYS[1],
|
||||
description=_DISABLE_KEYS[2],
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
# muultiplatform OS bits
|
||||
OSS = [('Linux', 0x0400), ('MacOS', 0x2000), ('Windows', 0x0100), ('iOS', 0x4000), ('Android', 0x1000), ('WebOS', 0x8000),
|
||||
('Chrome', 0x0800), ('WinEmb', 0x0200), ('Tizen', 0x0001)]
|
||||
|
||||
|
||||
def _feature_multiplatform_choices(device):
|
||||
def _str_os_versions(low, high):
|
||||
def _str_os_version(version):
|
||||
if version == 0:
|
||||
return ''
|
||||
elif version & 0xFF:
|
||||
return str(version >> 8) + '.' + str(version & 0xFF)
|
||||
else:
|
||||
return str(version >> 8)
|
||||
|
||||
return '' if low == 0 and high == 0 else ' ' + _str_os_version(low) + '-' + _str_os_version(high)
|
||||
|
||||
infos = device.feature_request(_F.MULTIPLATFORM)
|
||||
assert infos, 'Oops, multiplatform count cannot be retrieved!'
|
||||
flags, _ignore, num_descriptors = _unpack('!BBB', infos[:3])
|
||||
if not (flags & 0x02): # can't set platform so don't create setting
|
||||
return []
|
||||
descriptors = []
|
||||
for index in range(0, num_descriptors):
|
||||
descriptor = device.feature_request(_F.MULTIPLATFORM, 0x10, index)
|
||||
platform, _ignore, os_flags, low, high = _unpack('!BBHHH', descriptor[:8])
|
||||
descriptors.append((platform, os_flags, low, high))
|
||||
choices = _NamedInts()
|
||||
for os_name, os_bit in OSS:
|
||||
for platform, os_flags, low, high in descriptors:
|
||||
os = os_name + _str_os_versions(low, high)
|
||||
if os_bit & os_flags and platform not in choices and os not in choices:
|
||||
choices[platform] = os
|
||||
return choices
|
||||
|
||||
|
||||
def _feature_multiplatform():
|
||||
return feature_choices_dynamic(
|
||||
_PLATFORM[0],
|
||||
_F.MULTIPLATFORM,
|
||||
_feature_multiplatform_choices,
|
||||
read_fnid=0x00,
|
||||
read_skip_bytes_count=6,
|
||||
write_fnid=0x30,
|
||||
write_prefix_bytes=b'\xff',
|
||||
label=_PLATFORM[1],
|
||||
description=_PLATFORM[2],
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
PLATFORMS = _NamedInts()
|
||||
PLATFORMS[0x00] = 'iOS, MacOS'
|
||||
PLATFORMS[0x01] = 'Android, Windows'
|
||||
|
||||
|
||||
def _feature_dualplatform():
|
||||
return feature_choices(
|
||||
_PLATFORM[0],
|
||||
_F.DUALPLATFORM,
|
||||
PLATFORMS,
|
||||
read_fnid=0x10,
|
||||
write_fnid=0x20,
|
||||
label=_PLATFORM[1],
|
||||
description=_PLATFORM[2],
|
||||
device_kind=(_DK.keyboard, )
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
@ -681,6 +678,8 @@ _SETTINGS_TABLE = [
|
|||
_S(_BACKLIGHT[0], _F.BACKLIGHT2, _feature_backlight2),
|
||||
_S(_REPROGRAMMABLE_KEYS[0], _F.REPROG_CONTROLS_V4, _feature_reprogrammable_keys),
|
||||
_S(_DISABLE_KEYS[0], _F.KEYBOARD_DISABLE_KEYS, _feature_disable_keyboard_keys),
|
||||
_S(_PLATFORM[0], _F.MULTIPLATFORM, _feature_multiplatform),
|
||||
_S(_PLATFORM[0], _F.DUALPLATFORM, _feature_dualplatform, identifier='dualplatform')
|
||||
]
|
||||
|
||||
_SETTINGS_LIST = namedtuple('_SETTINGS_LIST', [s[4] for s in _SETTINGS_TABLE])
|
||||
|
|
|
@ -90,7 +90,7 @@ def _create_choice_control(setting):
|
|||
c = Gtk.ComboBoxText()
|
||||
# TODO i18n text entries
|
||||
for entry in setting.choices:
|
||||
c.append(str(entry), str(entry))
|
||||
c.append(str(int(entry)), str(entry))
|
||||
c.connect('changed', _combo_notify, setting)
|
||||
return c
|
||||
|
||||
|
@ -114,7 +114,7 @@ def _create_map_choice_control(setting):
|
|||
def _map_populate_value_box(valueBox, setting, key_choice):
|
||||
choices = None
|
||||
choices = setting.choices[key_choice]
|
||||
current = setting._value.get(str(key_choice)) # just in case the persisted value is missing some keys
|
||||
current = setting._value.get(str(key_choice)) if setting._value else None
|
||||
if choices:
|
||||
# TODO i18n text entries
|
||||
for choice in choices:
|
||||
|
|
Loading…
Reference in New Issue