settings: add setting for HAPTIC feature
This commit is contained in:
@@ -66,6 +66,7 @@ class SupportedFeature(IntEnum):
|
||||
BACKLIGHT3 = 0x1983
|
||||
ILLUMINATION = 0x1990
|
||||
FORCE_SENSING_BUTTON = 0x19C0
|
||||
HAPTIC = 0x19B0
|
||||
PRESENTER_CONTROL = 0x1A00
|
||||
SENSOR_3D = 0x1A01
|
||||
REPROG_CONTROLS = 0x1B00
|
||||
@@ -277,3 +278,23 @@ class ParamId(IntEnum):
|
||||
PIXEL_ZONE = 2 # 4 2-byte integers, left, bottom, width, height; pixels
|
||||
RATIO_ZONE = 3 # 4 bytes, left, bottom, width, height; unit 1/240 pad size
|
||||
SCALE_FACTOR = 4 # 2-byte integer, with 256 as normal scale
|
||||
|
||||
|
||||
HapticWaveForms = NamedInts(
|
||||
SHARP_STATE_CHANGE=0x00,
|
||||
DAMP_STATE_CHANGE=0x01,
|
||||
SHARP_COLLISION=0x02,
|
||||
DAMP_COLLISION=0x03,
|
||||
SUBTLE_COLLISION=0x04,
|
||||
HAPPY_ALERT=0x05,
|
||||
ANGRY_ALERT=0x06,
|
||||
COMPLETED=0x07,
|
||||
SQUARE=0x08,
|
||||
WAVE=0x09,
|
||||
FIREWORK=0x0A,
|
||||
MAD=0x0B,
|
||||
KNOCK=0x0C,
|
||||
JINGLE=0x0D,
|
||||
RINGING=0xE,
|
||||
WHISPER_COLLISION=0x1B,
|
||||
)
|
||||
|
||||
@@ -57,6 +57,7 @@ class Setting:
|
||||
rw_options = {}
|
||||
validator_class = None
|
||||
validator_options = {}
|
||||
display = True # display setting in UI
|
||||
|
||||
def __init__(self, device, rw, validator):
|
||||
self._device = device
|
||||
|
||||
@@ -40,6 +40,7 @@ class Setting:
|
||||
choices_universe = None # All possible acceptable keys, for settings with keys
|
||||
kind = Kind.NONE # What GUI interface to use
|
||||
persist = True # Whether to remember the setting
|
||||
display = True # display setting in UI
|
||||
_device = None # The device that this setting is for
|
||||
_device_object = None # The object that interacts with the feature for the device
|
||||
_value = None # Stored value as maintained by Solaar, used for persistence
|
||||
|
||||
@@ -1809,6 +1809,72 @@ class ForceSensing(settings_new.Settings):
|
||||
return setting
|
||||
|
||||
|
||||
class HapticLevel(settings.Setting):
|
||||
name = "haptic-level"
|
||||
label = _("Haptic Feeback Level")
|
||||
description = _("Change power of haptic feedback. (Zero to turn off.)")
|
||||
feature = _F.HAPTIC
|
||||
choices_universe = common.NamedInts(Off=0, Low=25, Medium=50, High=75, Maximum=100)
|
||||
min_value = 0
|
||||
max_value = 100
|
||||
|
||||
class rw_class(settings.FeatureRW):
|
||||
def __init__(self, feature):
|
||||
super().__init__(feature, read_fnid=0x10, write_fnid=0x20)
|
||||
|
||||
def read(self, device, data_bytes=b""):
|
||||
result = device.feature_request(self.feature, 0x10)
|
||||
if result[0] & 0x01 == 0: # disabled, return 0
|
||||
return b"\x00"
|
||||
else: # enabled, return second byte
|
||||
return result[1:2]
|
||||
|
||||
def write(self, device, data_bytes):
|
||||
if data_bytes == b"\x00":
|
||||
write_bytes = b"\x00\x32" # disable, at 50 percent
|
||||
else:
|
||||
write_bytes = b"\x01" + data_bytes
|
||||
reply = device.feature_request(self.feature, 0x20, write_bytes)
|
||||
return reply
|
||||
|
||||
@classmethod
|
||||
def build(cls, device):
|
||||
response = device.feature_request(cls.feature, 0x10)
|
||||
if response:
|
||||
rw = cls.rw_class(cls.feature)
|
||||
levels = response[2] & 0x01
|
||||
if levels: # device only has four levels
|
||||
validator = settings_validator.ChoicesValidator(choices=cls.choices_universe)
|
||||
else: # device has all levels
|
||||
validator = settings_validator.RangeValidator(min_value=cls.min_value, max_value=cls.max_value)
|
||||
return cls(device, rw, validator)
|
||||
|
||||
|
||||
# This setting is not displayed in the UI
|
||||
# Use `solaar config <device> haptic-play <form>` to play a haptic form
|
||||
class PlayHapticWaveForm(settings.Setting):
|
||||
name = "haptic-play"
|
||||
label = _("Play Haptic Waveform")
|
||||
description = _("Tell device to play a haptic waveform.")
|
||||
feature = _F.HAPTIC
|
||||
choices_universe = hidpp20_constants.HapticWaveForms
|
||||
rw_options = {"read_fnid": None, "write_fnid": 0x40} # nothing to read
|
||||
persist = False # persisting this setting is useless
|
||||
display = False # don't display in UI, interact using `solaar config ...`
|
||||
|
||||
class validator_class(settings_validator.ChoicesValidator):
|
||||
@classmethod
|
||||
def build(cls, setting_class, device):
|
||||
response = device.feature_request(_F.HAPTIC, 0x00)
|
||||
if response:
|
||||
waves = common.NamedInts()
|
||||
waveforms = int.from_bytes(response[4:8])
|
||||
for waveform in hidpp20_constants.HapticWaveForms:
|
||||
if (1 << int(waveform)) & waveforms:
|
||||
waves[int(waveform)] = str(waveform)
|
||||
return cls(choices=waves, byte_count=1)
|
||||
|
||||
|
||||
SETTINGS: list[settings.Setting] = [
|
||||
RegisterHandDetection, # simple
|
||||
RegisterSmoothScroll, # simple
|
||||
@@ -1866,6 +1932,8 @@ SETTINGS: list[settings.Setting] = [
|
||||
Gesture2Gestures, # working
|
||||
Gesture2Divert,
|
||||
Gesture2Params, # working
|
||||
HapticLevel,
|
||||
PlayHapticWaveForm,
|
||||
Sidetone,
|
||||
Equalizer,
|
||||
ADCPower,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
from enum import Enum
|
||||
from threading import Timer
|
||||
@@ -70,7 +69,6 @@ def _write_async(setting, value, sbox, sensitive=True, key=None):
|
||||
v = setting.write_key_value(key, v)
|
||||
v = {key: v}
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
v = None
|
||||
if sb:
|
||||
GLib.idle_add(_update_setting_item, sb, v, True, sensitive, priority=99)
|
||||
@@ -660,6 +658,8 @@ def _change_icon(allowed, icon):
|
||||
|
||||
|
||||
def _create_sbox(s, _device):
|
||||
if not s.display:
|
||||
return
|
||||
sbox = Gtk.HBox(homogeneous=False, spacing=6)
|
||||
sbox.setting = s
|
||||
sbox.kind = s.kind
|
||||
|
||||
Reference in New Issue
Block a user