Add M185 keys reporting using REPROG CONTROLS V4 in cli

Add smooth scrolling using LOWRES_WHEEL
Add mouse speed selection using POINTER_SPEED
This commit is contained in:
Alex Cherkayev 2017-02-12 20:55:50 +02:00
parent db0656967b
commit f9618dd0ab
4 changed files with 62 additions and 5 deletions

View File

@ -279,4 +279,14 @@ ReprogrammableKeyInfo = namedtuple('ReprogrammableKeyInfo', [
'task', 'task',
'flags']) 'flags'])
ReprogrammableKeyInfoV4 = namedtuple('ReprogrammableKeyInfoV4', [
'index',
'key',
'task',
'flags',
'pos',
'group',
'group_mask',
'remapped'])
del namedtuple del namedtuple

View File

@ -28,6 +28,7 @@ del getLogger
from .common import (FirmwareInfo as _FirmwareInfo, from .common import (FirmwareInfo as _FirmwareInfo,
ReprogrammableKeyInfo as _ReprogrammableKeyInfo, ReprogrammableKeyInfo as _ReprogrammableKeyInfo,
ReprogrammableKeyInfoV4 as _ReprogrammableKeyInfoV4,
KwException as _KwException, KwException as _KwException,
NamedInts as _NamedInts, NamedInts as _NamedInts,
pack as _pack, pack as _pack,
@ -300,11 +301,12 @@ class FeaturesArray(object):
class KeysArray(object): class KeysArray(object):
"""A sequence of key mappings supported by a HID++ 2.0 device.""" """A sequence of key mappings supported by a HID++ 2.0 device."""
__slots__ = ('device', 'keys') __slots__ = ('device', 'keys', 'keyversion')
def __init__(self, device, count): def __init__(self, device, count):
assert device is not None assert device is not None
self.device = device self.device = device
self.keyversion = 0
self.keys = [None] * count self.keys = [None] * count
def __getitem__(self, index): def __getitem__(self, index):
@ -312,13 +314,28 @@ class KeysArray(object):
if index < 0 or index >= len(self.keys): if index < 0 or index >= len(self.keys):
raise IndexError(index) raise IndexError(index)
# TODO: add here additional variants for other REPROG_CONTROLS
if self.keys[index] is None: if self.keys[index] is None:
keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS, 0x10, index) keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS, 0x10, index)
self.keyversion=1
if keydata is None:
keydata = feature_request(self.device, FEATURE.REPROG_CONTROLS_V4, 0x10, index)
self.keyversion=4
if keydata: if keydata:
key, key_task, flags = _unpack('!HHB', keydata[:5]) key, key_task, flags, pos, group, gmask = _unpack('!HHBBBB', keydata[:8])
ctrl_id_text = special_keys.CONTROL[key] ctrl_id_text = special_keys.CONTROL[key]
ctrl_task_text = special_keys.TASK[key_task] ctrl_task_text = special_keys.TASK[key_task]
if self.keyversion == 1:
self.keys[index] = _ReprogrammableKeyInfo(index, ctrl_id_text, ctrl_task_text, flags) self.keys[index] = _ReprogrammableKeyInfo(index, ctrl_id_text, ctrl_task_text, flags)
if self.keyversion == 4:
mapped_data = feature_request(self.device, FEATURE.REPROG_CONTROLS_V4, 0x20, key&0xff00, key&0xff)
if mapped_data:
remap_key, remap_flag, remapped = _unpack('!HBH', mapped_data[:5])
# if key not mapped map it to itself for display
if remapped == 0:
remapped = key
remapped_text = special_keys.CONTROL[remapped]
self.keys[index] = _ReprogrammableKeyInfoV4(index, ctrl_id_text, ctrl_task_text, flags, pos, group, gmask, remapped_text)
return self.keys[index] return self.keys[index]
@ -439,7 +456,10 @@ def get_battery(device):
def get_keys(device): def get_keys(device):
# TODO: add here additional variants for other REPROG_CONTROLS
count = feature_request(device, FEATURE.REPROG_CONTROLS) count = feature_request(device, FEATURE.REPROG_CONTROLS)
if count is None:
count = feature_request(device, FEATURE.REPROG_CONTROLS_V4)
if count: if count:
return KeysArray(device, ord(count[:1])) return KeysArray(device, ord(count[:1]))

View File

@ -122,6 +122,7 @@ _SIDE_SCROLL = ('side-scroll', _("Side Scrolling"),
_("When disabled, pushing the wheel sideways sends custom button events\n" _("When disabled, pushing the wheel sideways sends custom button events\n"
"instead of the standard side-scrolling events.")) "instead of the standard side-scrolling events."))
_DPI = ('dpi', _("Sensitivity (DPI)"), None) _DPI = ('dpi', _("Sensitivity (DPI)"), None)
_POINTER_SPEED = ('pointer_speed', _("Sensitivity (Pointer Speed)"), None)
_FN_SWAP = ('fn-swap', _("Swap Fx function"), _FN_SWAP = ('fn-swap', _("Swap Fx function"),
_("When set, the F1..F12 keys will activate their special function,\n" _("When set, the F1..F12 keys will activate their special function,\n"
"and you must hold the FN key to activate their standard function.") "and you must hold the FN key to activate their standard function.")
@ -179,6 +180,11 @@ def _feature_smooth_scroll():
label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2], label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2],
device_kind=_DK.mouse) device_kind=_DK.mouse)
def _feature_lowres_smooth_scroll():
return feature_toggle(_SMOOTH_SCROLL[0], _F.LOWRES_WHEEL,
label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2],
device_kind=_DK.mouse)
def _feature_smart_shift(): def _feature_smart_shift():
_MIN_SMART_SHIFT_VALUE = 0 _MIN_SMART_SHIFT_VALUE = 0
_MAX_SMART_SHIFT_VALUE = 50 _MAX_SMART_SHIFT_VALUE = 50
@ -250,6 +256,15 @@ def _feature_adjustable_dpi():
label=_DPI[1], description=_DPI[2], label=_DPI[1], description=_DPI[2],
device_kind=_DK.mouse) device_kind=_DK.mouse)
def _feature_pointer_speed():
"""Pointer Speed feature"""
# min and max values taken from usb traces of Win software
return feature_range(_POINTER_SPEED[0], _F.POINTER_SPEED, 0x002e, 0x01ff,
read_function_id=0x0,
write_function_id=0x10,
bytes_count=2,
label=_POINTER_SPEED[1], description=_POINTER_SPEED[2],
device_kind=_DK.mouse)
# #
# #
# #
@ -259,8 +274,10 @@ _SETTINGS_LIST = namedtuple('_SETTINGS_LIST', [
'fn_swap', 'fn_swap',
'new_fn_swap', 'new_fn_swap',
'smooth_scroll', 'smooth_scroll',
'lowres_smooth_scroll',
'side_scroll', 'side_scroll',
'dpi', 'dpi',
'pointer_speed',
'hand_detection', 'hand_detection',
'typing_illumination', 'typing_illumination',
'smart_shift', 'smart_shift',
@ -271,8 +288,10 @@ RegisterSettings = _SETTINGS_LIST(
fn_swap=_register_fn_swap, fn_swap=_register_fn_swap,
new_fn_swap=None, new_fn_swap=None,
smooth_scroll=_register_smooth_scroll, smooth_scroll=_register_smooth_scroll,
lowres_smooth_scroll=None,
side_scroll=_register_side_scroll, side_scroll=_register_side_scroll,
dpi=_register_dpi, dpi=_register_dpi,
pointer_speed=None,
hand_detection=_register_hand_detection, hand_detection=_register_hand_detection,
typing_illumination=None, typing_illumination=None,
smart_shift=None, smart_shift=None,
@ -281,8 +300,10 @@ FeatureSettings = _SETTINGS_LIST(
fn_swap=_feature_fn_swap, fn_swap=_feature_fn_swap,
new_fn_swap=_feature_new_fn_swap, new_fn_swap=_feature_new_fn_swap,
smooth_scroll=_feature_smooth_scroll, smooth_scroll=_feature_smooth_scroll,
lowres_smooth_scroll=_feature_lowres_smooth_scroll,
side_scroll=None, side_scroll=None,
dpi=_feature_adjustable_dpi, dpi=_feature_adjustable_dpi,
pointer_speed=_feature_pointer_speed,
hand_detection=None, hand_detection=None,
typing_illumination=None, typing_illumination=None,
smart_shift=_feature_smart_shift, smart_shift=_feature_smart_shift,
@ -320,7 +341,9 @@ def check_feature_settings(device, already_known):
already_known.append(feature(device)) already_known.append(feature(device))
check_feature(_SMOOTH_SCROLL[0], _F.HI_RES_SCROLLING) check_feature(_SMOOTH_SCROLL[0], _F.HI_RES_SCROLLING)
check_feature(_SMOOTH_SCROLL[0], _F.LOWRES_WHEEL)
check_feature(_FN_SWAP[0], _F.FN_INVERSION) check_feature(_FN_SWAP[0], _F.FN_INVERSION)
check_feature(_FN_SWAP[0], _F.NEW_FN_INVERSION, 'new_fn_swap') check_feature(_FN_SWAP[0], _F.NEW_FN_INVERSION, 'new_fn_swap')
check_feature(_DPI[0], _F.ADJUSTABLE_DPI) check_feature(_DPI[0], _F.ADJUSTABLE_DPI)
check_feature(_POINTER_SPEED[0], _F.POINTER_SPEED)
check_feature(_SMART_SHIFT[0], _F.SMART_SHIFT) check_feature(_SMART_SHIFT[0], _F.SMART_SHIFT)

View File

@ -98,8 +98,12 @@ def _print_device(dev):
print (' Has %d reprogrammable keys:' % len(dev.keys)) print (' Has %d reprogrammable keys:' % len(dev.keys))
for k in dev.keys: for k in dev.keys:
flags = _special_keys.KEY_FLAG.flag_names(k.flags) flags = _special_keys.KEY_FLAG.flag_names(k.flags)
# TODO: add here additional variants for other REPROG_CONTROLS
if dev.keys.keyversion == 1:
print (' %2d: %-26s => %-27s %s' % (k.index, k.key, k.task, ', '.join(flags))) print (' %2d: %-26s => %-27s %s' % (k.index, k.key, k.task, ', '.join(flags)))
if dev.keys.keyversion == 4:
print (' %2d: %-26s, default: %-27s => %-26s' % (k.index, k.key, k.task, k.remapped))
print (' %s, pos:%d, group:%1d, gmask:%d' % ( ', '.join(flags), k.pos, k.group, k.group_mask))
if dev.online: if dev.online:
battery = _hidpp20.get_battery(dev) battery = _hidpp20.get_battery(dev)
if battery is None: if battery is None: