settings: add setting for DPI CHANGE button to switch Sensitivity

This commit is contained in:
Peter F. Patel-Schneider 2021-09-26 22:16:21 -04:00
parent 2de79141e4
commit 14c1eac79c
2 changed files with 104 additions and 0 deletions

View File

@ -23,6 +23,7 @@ import math
from copy import copy as _copy
from logging import DEBUG as _DEBUG
from logging import WARNING as _WARNING
from logging import getLogger
## use regular time instead of time_ns so as not to require Python 3.7
# from time import time_ns as _time_ns
@ -1048,6 +1049,72 @@ class MultipleRangeValidator:
return w + b'\xFF'
class ActionSettingRW(object):
"""Special RW class for settings that turn on and off special processing when a key or button is depressed"""
def __init__(self, name, divert_setting_name):
self.name = name
self.divert_setting_name = divert_setting_name
self.kind = FeatureRW.kind # pretend to be FeatureRW as required for HID++ 2.0 devices
self.device = None
self.key = None
self.active = False
self.pressed = False
def press_action(self): # action to take when key is pressed
pass
def release_action(self): # action to take when key is released
pass
def move_action(self, dx, dy): # action to take when mouse is moved while key is down
pass
def read(self, device): # need to return bytes, as if read from device
return _int2bytes(self.key, 2) if self.active else b'\x00\x00'
def write(self, device, data_bytes):
def handler(device, n): # Called on notification events from the device
if n.sub_id < 0x40 and device.features[n.sub_id] == _hidpp20.FEATURE.REPROG_CONTROLS_V4:
if n.address == 0x00:
cids = _unpack('!HHHH', n.data[:8])
if not self.pressed and int(self.key.key) in cids:
self.pressed = True
self.press_action()
elif self.pressed and int(self.key.key) not in cids:
self.pressed = False
self.release_action()
elif n.address == 0x10:
if self.pressed:
dx, dy = _unpack('!hh', n.data[:4])
self.move_action(dx, dy)
divertSetting = next(filter(lambda s: s.name == self.divert_setting_name, device.settings), None)
self.device = device
key = _bytes2int(data_bytes)
if key: # Enable
self.key = next((k for k in device.keys if k.key == key), None)
if self.key:
self.active = True
divertSetting.write_key_value(int(self.key.key), 1)
device.add_notification_handler(self.name, handler)
from solaar.ui import status_changed as _status_changed
_status_changed(device, refresh=True) # update main window
else:
_log.error('cannot enable %s on %s for key %s', self.name, device, key)
else: # Disable
if self.active:
self.active = False
divertSetting.write_key_value(int(self.key.key), 0)
from solaar.ui import status_changed as _status_changed
_status_changed(device, refresh=True) # update main window
try:
device.remove_notification_handler(self.name)
except Exception:
if _log.isEnabledFor(_WARNING):
_log.warn('cannot disable %s on %s', self.name, device)
return True
# Turn diverted mouse movement events into a mouse gesture
#
# Uses the following FSM.

View File

@ -35,6 +35,7 @@ from .common import bytes2int as _bytes2int
from .common import int2bytes as _int2bytes
from .common import unpack as _unpack
from .i18n import _
from .settings import ActionSettingRW as _ActionSettingRW
from .settings import BitFieldSetting as _BitFieldSetting
from .settings import BitFieldValidator as _BitFieldV
from .settings import BitFieldWithOffsetAndMaskSetting as _BitFieldOMSetting
@ -118,6 +119,9 @@ _DIVERT_CROWN = ('divert-crown', _('Divert crown events'),
_('Make crown send CROWN HID++ notifications (which trigger Solaar rules but are otherwise ignored).'))
_DIVERT_GKEYS = ('divert-gkeys', _('Divert G Keys'),
_('Make G keys send GKEY HID++ notifications (which trigger Solaar rules but are otherwise ignored).'))
_SPEED_CHANGE = ('speed-change', _('Sensitivity Switching'),
_('Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\n'
'If there is no remembered sensitivity, just remember the current sensitivity'))
_GESTURE2_GESTURES_LABELS = {
_GG['Tap1Finger']: (_('Single tap'), _('Performs a left click.')),
@ -524,6 +528,38 @@ def _feature_dpi_sliding():
return _Setting(_DPI_SLIDING, _DpiSlidingRW(), callback=_feature_dpi_sliding_callback, device_kind=(_DK.mouse, ))
def _feature_speed_change():
"""Implements the ability to switch Sensitivity by clicking on the DPI_Change button."""
class _SpeedChangeRW(_ActionSettingRW):
def press_action(self): # switch sensitivity
currentSpeed = self.device.persister.get('pointer_speed', None) if self.device.persister else None
newSpeed = self.device.persister.get('_speed-change', None) if self.device.persister else None
speed_setting = next(filter(lambda s: s.name == _POINTER_SPEED[0], self.device.settings), None)
if newSpeed is not None:
if speed_setting:
speed_setting.write(newSpeed)
else:
_log.error('cannot save sensitivity setting on %s', self.device)
from solaar.ui import status_changed as _status_changed
_status_changed(self.device, refresh=True) # update main window
if self.device.persister:
self.device.persister['_speed-change'] = currentSpeed
def callback(device):
key_index = device.keys.index(_special_keys.CONTROL.DPI_Change)
key = device.keys[key_index] if key_index is not None else None
if key is not None and 'divertable' in key.flags:
keys = [_NamedInt(0, _('Off')), key.key]
return _ChoicesV(_NamedInts.list(keys), byte_count=2)
return _Setting(
_SPEED_CHANGE,
_SpeedChangeRW('speed change', _DIVERT_KEYS[0]),
callback=callback,
device_kind=(_DK.mouse, _DK.trackball)
)
def _feature_adjustable_dpi_callback(device):
# [1] getSensorDpiList(sensorIdx)
reply = device.feature_request(_F.ADJUSTABLE_DPI, 0x10)
@ -852,6 +888,7 @@ _SETTINGS_TABLE = [
_S(_DPI_SLIDING, _F.REPROG_CONTROLS_V4, _feature_dpi_sliding),
_S(_MOUSE_GESTURES, _F.REPROG_CONTROLS_V4, _feature_mouse_gesture),
_S(_POINTER_SPEED, _F.POINTER_SPEED, _feature_pointer_speed),
_S(_SPEED_CHANGE, _F.POINTER_SPEED, _feature_speed_change),
_S(_BACKLIGHT, _F.BACKLIGHT2, _feature_backlight2),
_S(_FN_SWAP, _F.FN_INVERSION, _feature_fn_swap, registerFn=_register_fn_swap),
_S(_FN_SWAP, _F.NEW_FN_INVERSION, _feature_new_fn_swap, identifier='new_fn_swap'),