add angle snapping and debounce

This commit is contained in:
Kyoken
2022-12-09 14:18:44 +03:00
committed by Yaroslav Chvanov
parent 37628da52f
commit 51edc2967b
10 changed files with 516 additions and 3 deletions

View File

@@ -454,6 +454,40 @@ ratbagd_profile_get_report_rate(sd_bus *bus,
return sd_bus_message_append(reply, "u", rate);
}
static int
ratbagd_profile_get_angle_snapping(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbag_profile *lib_profile = profile->lib_profile;
int value;
value = ratbag_profile_get_angle_snapping(lib_profile);
return sd_bus_message_append(reply, "i", value);
}
static int
ratbagd_profile_get_debounce(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbag_profile *lib_profile = profile->lib_profile;
int value;
value = ratbag_profile_get_debounce(lib_profile);
return sd_bus_message_append(reply, "i", value);
}
static int
ratbagd_profile_get_report_rates(sd_bus *bus,
const char *path,
@@ -487,6 +521,37 @@ ratbagd_profile_get_report_rates(sd_bus *bus,
return sd_bus_message_close_container(reply);
}
static int
ratbagd_profile_get_debounces(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
struct ratbag_profile *lib_profile = profile->lib_profile;
unsigned int debounces[8];
unsigned int ndebounces = ARRAY_LENGTH(debounces);
int r;
r = sd_bus_message_open_container(reply, 'a', "u");
if (r < 0)
return r;
ndebounces = ratbag_profile_get_debounce_list(lib_profile, debounces, ndebounces);
assert(ndebounces <= ARRAY_LENGTH(debounces));
for (unsigned int i = 0; i < ndebounces; i++) {
verify_unsigned_int(debounces[i]);
r = sd_bus_message_append(reply, "u", debounces[i]);
if (r < 0)
return r;
}
return sd_bus_message_close_container(reply);
}
static int
ratbagd_profile_set_report_rate(sd_bus *bus,
@@ -521,6 +586,66 @@ ratbagd_profile_set_report_rate(sd_bus *bus,
return 0;
}
static int
ratbagd_profile_set_angle_snapping(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
int value;
int r;
r = sd_bus_message_read(m, "i", &value);
if (r < 0)
return r;
r = ratbag_profile_set_angle_snapping(profile->lib_profile, value);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
profile->path,
RATBAGD_NAME_ROOT ".Profile",
"AngleSnapping",
NULL);
}
return 0;
}
static int
ratbagd_profile_set_debounce(sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *m,
void *userdata,
sd_bus_error *error)
{
struct ratbagd_profile *profile = userdata;
int value;
int r;
r = sd_bus_message_read(m, "i", &value);
if (r < 0)
return r;
r = ratbag_profile_set_debounce(profile->lib_profile, value);
if (r == 0) {
sd_bus *bus = sd_bus_message_get_bus(m);
sd_bus_emit_properties_changed(bus,
profile->path,
RATBAGD_NAME_ROOT ".Profile",
"Debounce",
NULL);
}
return 0;
}
const sd_bus_vtable ratbagd_profile_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_WRITABLE_PROPERTY("Name", "s",
@@ -541,7 +666,16 @@ const sd_bus_vtable ratbagd_profile_vtable[] = {
ratbagd_profile_get_report_rate,
ratbagd_profile_set_report_rate, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("AngleSnapping", "i",
ratbagd_profile_get_angle_snapping,
ratbagd_profile_set_angle_snapping, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_WRITABLE_PROPERTY("Debounce", "i",
ratbagd_profile_get_debounce,
ratbagd_profile_set_debounce, 0,
SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ReportRates", "au", ratbagd_profile_get_report_rates, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Debounces", "au", ratbagd_profile_get_debounces, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("SetActive", "", "u", ratbagd_profile_set_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};

View File

@@ -76,6 +76,7 @@ static const unsigned char ASUS_KEY_MAPPING[] = {
};
static unsigned int ASUS_POLLING_RATES[] = { 125, 250, 500, 1000 };
static unsigned int ASUS_DEBOUNCE_TIMES[] = { 4, 8, 12, 16, 20, 24, 28, 32 };
/* search for ASUS button by ratbag types */
const struct asus_button *
@@ -147,6 +148,8 @@ asus_setup_profile(struct ratbag_device *device, struct ratbag_profile *profile)
{
ratbag_profile_set_report_rate_list(
profile, ASUS_POLLING_RATES, ARRAY_LENGTH(ASUS_POLLING_RATES));
ratbag_profile_set_debounce_list(
profile, ASUS_DEBOUNCE_TIMES, ARRAY_LENGTH(ASUS_DEBOUNCE_TIMES));
}
void
@@ -311,6 +314,7 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat
data->data2.dpi[i] *= 2;
}
data->data2.rate = ASUS_POLLING_RATES[data->data2.rate];
data->data2.response = ASUS_DEBOUNCE_TIMES[data->data2.response];
break;
case 4: /* 4 DPI presets */
@@ -320,6 +324,7 @@ asus_get_resolution_data(struct ratbag_device *device, union asus_resolution_dat
data->data4.dpi[i] *= 2;
}
data->data4.rate = ASUS_POLLING_RATES[data->data4.rate];
data->data4.response = ASUS_DEBOUNCE_TIMES[data->data4.response];
break;
default:
@@ -392,11 +397,18 @@ asus_set_button_response(struct ratbag_device *device, unsigned int ms)
int rc;
unsigned int dpi_count = ratbag_device_get_profile(device, 0)->num_resolutions;
union asus_response response;
unsigned int index = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH(ASUS_DEBOUNCE_TIMES); i++) {
if (ASUS_DEBOUNCE_TIMES[i] == ms) {
index = i;
break;
}
}
union asus_request request = {
.data.cmd = ASUS_CMD_SET_SETTING,
.data.params[0] = dpi_count + ASUS_FIELD_RESPONSE, /* field index to set */
.data.params[2] = ms / 4 - 1,
.data.params[2] = index,
};
rc = asus_query(device, &request, &response);

View File

@@ -148,6 +148,8 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr
switch (dpi_count) {
case 2: /* 2 DPI presets */
ratbag_profile_set_report_rate(profile, resolution_data.data2.rate);
ratbag_profile_set_angle_snapping(profile, resolution_data.data2.snapping);
ratbag_profile_set_debounce(profile, resolution_data.data2.response);
ratbag_profile_for_each_resolution(profile, resolution)
ratbag_resolution_set_resolution(
resolution,
@@ -157,6 +159,8 @@ asus_driver_load_profile(struct ratbag_device *device, struct ratbag_profile *pr
case 4: /* 4 DPI presets */
ratbag_profile_set_report_rate(profile, resolution_data.data4.rate);
ratbag_profile_set_angle_snapping(profile, resolution_data.data4.snapping);
ratbag_profile_set_debounce(profile, resolution_data.data4.response);
ratbag_profile_for_each_resolution(profile, resolution)
ratbag_resolution_set_resolution(
resolution,
@@ -265,6 +269,18 @@ asus_driver_save_profile(struct ratbag_device *device, struct ratbag_profile *pr
if (rc)
return rc;
}
if (profile->angle_snapping_dirty) {
log_debug(device->ratbag, "Angle snapping changed to %d\n", profile->angle_snapping);
rc = asus_set_angle_snapping(device, profile->angle_snapping);
if (rc)
return rc;
}
if (profile->debounce_dirty) {
log_debug(device->ratbag, "Debounce time changed to %d\n", profile->debounce);
rc = asus_set_button_response(device, profile->debounce);
if (rc)
return rc;
}
/* set DPIs */
ratbag_profile_for_each_resolution(profile, resolution) {

View File

@@ -267,6 +267,14 @@ struct ratbag_profile {
size_t nrates; /**< number of entries in rates */
bool rate_dirty;
int angle_snapping;
bool angle_snapping_dirty;
int debounce; /**< debounce time in ms */
bool debounce_dirty;
unsigned int debounces[8]; /**< debounce times available */
size_t ndebounces; /**< number of entries in debounces */
unsigned int num_resolutions;
bool is_active; /**< profile is the currently active one */
@@ -538,6 +546,22 @@ ratbag_profile_set_report_rate_list(struct ratbag_profile *profile,
profile->nrates = nrates;
}
static inline void
ratbag_profile_set_debounce_list(struct ratbag_profile *profile,
const unsigned int *values,
size_t nvalues)
{
assert(nvalues <= ARRAY_LENGTH(profile->debounces));
_Static_assert(sizeof(*values) == sizeof(*profile->debounces), "Mismatching size");
for (size_t i = 0; i < nvalues; i++) {
profile->debounces[i] = values[i];
if (i > 0)
assert(values[i] > values[i - 1]);
}
profile->ndebounces = nvalues;
}
static inline void
ratbag_resolution_set_cap(struct ratbag_resolution *res,
enum ratbag_resolution_capability cap)
@@ -594,4 +618,3 @@ ratbag_register_driver(struct ratbag *ratbag, struct ratbag_driver *driver);
void
ratbag_button_copy_macro(struct ratbag_button *button,
const struct ratbag_button_macro *macro);

View File

@@ -697,6 +697,8 @@ ratbag_create_profile(struct ratbag_device *device,
profile->num_resolutions = 0;
profile->is_enabled = true;
profile->name = NULL;
profile->angle_snapping = -1;
profile->debounce = -1;
list_append(&device->profiles, &profile->link);
list_init(&profile->buttons);
@@ -863,6 +865,8 @@ ratbag_device_commit(struct ratbag_device *device)
list_for_each(profile, &device->profiles, link) {
profile->dirty = false;
profile->angle_snapping_dirty = false;
profile->debounce_dirty = false;
profile->rate_dirty = false;
list_for_each(button, &profile->buttons, link)
@@ -1034,6 +1038,32 @@ ratbag_profile_set_report_rate(struct ratbag_profile *profile,
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_profile_set_angle_snapping(struct ratbag_profile *profile,
int value)
{
if (profile->angle_snapping != value) {
profile->angle_snapping = value;
profile->dirty = true;
profile->angle_snapping_dirty = true;
}
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT enum ratbag_error_code
ratbag_profile_set_debounce(struct ratbag_profile *profile,
int value)
{
if (profile->debounce != value) {
profile->debounce = value;
profile->dirty = true;
profile->debounce_dirty = true;
}
return RATBAG_SUCCESS;
}
LIBRATBAG_EXPORT int
ratbag_resolution_get_dpi(struct ratbag_resolution *resolution)
{
@@ -1076,6 +1106,36 @@ ratbag_profile_get_report_rate(struct ratbag_profile *profile)
return profile->hz;
}
LIBRATBAG_EXPORT int
ratbag_profile_get_angle_snapping(struct ratbag_profile *profile)
{
return profile->angle_snapping;
}
LIBRATBAG_EXPORT int
ratbag_profile_get_debounce(struct ratbag_profile *profile)
{
return profile->debounce;
}
LIBRATBAG_EXPORT size_t
ratbag_profile_get_debounce_list(struct ratbag_profile *profile,
unsigned int *debounces,
size_t ndebounces)
{
_Static_assert(sizeof(*debounces) == sizeof(*profile->debounces), "type mismatch");
assert(ndebounces > 0);
if (profile->ndebounces == 0)
return 0;
memcpy(debounces, profile->debounces,
sizeof(unsigned int) * min(ndebounces, profile->ndebounces));
return profile->ndebounces;
}
LIBRATBAG_EXPORT size_t
ratbag_profile_get_report_rate_list(struct ratbag_profile *profile,
unsigned int *rates,

View File

@@ -769,6 +769,90 @@ ratbag_profile_get_report_rate_list(struct ratbag_profile *profile,
unsigned int *rates,
size_t nrates);
/**
* @ingroup profile
*
* Set the angle snapping option for the profile.
*
* A value of 0 disables the mode.
*
* If the profile mode is the currently active profile,
* the change takes effect immediately.
*
* @param profile A previously initialized ratbag profile
* @param value Angle snapping value
*
* @return zero on success or an error code on failure
*/
enum ratbag_error_code
ratbag_profile_set_angle_snapping(struct ratbag_profile *profile,
int value);
/**
* @ingroup profile
*
* Get the angle snapping option for the profile.
*
* @param profile A previously initialized ratbag profile
*
* @return Angle snapping value
*/
int
ratbag_profile_get_angle_snapping(struct ratbag_profile *profile);
/**
* @ingroup profile
*
* Set the debounce time in ms for the profile.
*
* If the profile mode is the currently active profile,
* the change takes effect immediately.
*
* @param profile A previously initialized ratbag profile
* @param value Debounce time in ms
*
* @return zero on success or an error code on failure
*/
enum ratbag_error_code
ratbag_profile_set_debounce(struct ratbag_profile *profile,
int value);
/**
* @ingroup profile
*
* Get the debounce time in ms for the profile.
*
* @param profile A previously initialized ratbag profile
*
* @return Debounce time for this profile in ms
*/
int
ratbag_profile_get_debounce(struct ratbag_profile *profile);
/**
* @ingroup profile
*
* Get the number of debounce times in ms available for this profile.
* The list of debounce times is sorted in ascending order but may be filtered
* by libratbag and does not necessarily reflect all debounce times supported by
* the physical device.
*
* This function writes at most ndebounces values but returns the number of
* debounce times available on this resolution. In other words, if it returns a
* number larger than ndebounces, call it again with an array the size of the
* return value.
*
* @param[out] debounces Set to the supported debounce times in ascending order
* @param[in] ndebounces The number of elements
*
* @return The number of valid items in values. If the returned value
* is larger than ndebounces, the list was truncated.
*/
size_t
ratbag_profile_get_debounce_list(struct ratbag_profile *profile,
unsigned int *debounces,
size_t ndebounces);
/**
* @ingroup profile
*
@@ -1684,4 +1768,3 @@ ratbag_led_ref(struct ratbag_led *led);
*/
struct ratbag_led *
ratbag_led_unref(struct ratbag_led *led);

View File

@@ -52,6 +52,13 @@
%typemap(freearg) (unsigned int *rates, size_t nrates) = (unsigned int *resolutions, size_t nres);
/* END OF custom typemap for handling ratbag_resolution_get_report_rate_list */
/* custom typemap for handling lists */
/* We re-use the ratbag_profile_get_debounce_list typemap */
%typemap(in) (unsigned int *debounces, size_t ndebounces) = (unsigned int *resolutions, size_t nres);
%typemap(argout) (unsigned int *debounces, size_t ndebounces) = (unsigned int *resolutions, size_t nres);
%typemap(freearg) (unsigned int *debounces, size_t ndebounces) = (unsigned int *resolutions, size_t nres);
/* END OF custom typemap for handling ratbag_resolution_get_report_rate_list */
/* uintXX_t mapping: Python -> C */
%typemap(in) uint8_t {
$1 = (uint8_t) PyInt_AsLong($input);

View File

@@ -437,6 +437,39 @@ class RatbagdProfile(metaclass=MetaRatbag):
n = libratbag.ratbag_resolution_get_report_rate_list(self._profile, rates)
return rates[:n]
@property
def angle_snapping(self):
"""The angle snapping option."""
return libratbag.ratbag_profile_get_angle_snapping(self._profile)
@angle_snapping.setter
def angle_snapping(self, value):
"""Set the angle snapping option.
@param value The angle snapping option as bool
"""
libratbag.ratbag_profile_set_angle_snapping(self._profile, value)
@property
def debounce(self):
"""The debounce time in ms."""
return libratbag.ratbag_profile_get_debounce(self._profile)
@debounce.setter
def debounce(self, value):
"""Set the debounce time in ms.
@param value The new debounce time, as int
"""
libratbag.ratbag_profile_set_debounce(self._profile, value)
@property
def debounces(self):
"""The list of supported debounce times"""
values = [0 for i in range(300)]
n = libratbag.ratbag_profile_get_debounce_list(self._profile, values)
return values[:n]
@property
def resolutions(self):
"""A list of RatbagdResolution objects with this profile's resolutions.

View File

@@ -278,6 +278,10 @@ def print_profile(device: RatbagdDevice, profile: RatbagdProfile, level: int) ->
print(" " * level + "Resolutions:")
for resolution in profile.resolutions:
print_resolution(device, profile, resolution, level + 2)
if profile.angle_snapping != -1:
print(" " * level + f"Angle Snapping: {bool(profile.angle_snapping)}")
if profile.debounce != -1:
print(" " * level + f"Debounce time: {profile.debounce}ms")
if profile.buttons:
for button in profile.buttons:
print_button(device, profile, button, level)
@@ -517,6 +521,38 @@ def func_report_rate_set(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
commit(device, args)
def func_angle_snapping_get(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
profile, _device = find_profile(ratbagd, args)
if profile.angle_snapping == -1:
return None
print(bool(profile.angle_snapping))
def func_angle_snapping_set(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
profile, device = find_profile(ratbagd, args)
profile.angle_snapping = 1 if args.angle_snapping_n else 0
commit(device, args)
def func_debounce_get(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
profile, _device = find_profile(ratbagd, args)
if profile.debounce == -1:
return None
print(profile.debounce)
def func_debounce_get_all(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
profile, _device = find_profile(ratbagd, args)
values = profile.debounces
print(" ".join([str(x) for x in values]))
def func_debounce_set(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
profile, device = find_profile(ratbagd, args)
profile.debounce = args.debounce_n
commit(device, args)
def func_resolution_get(ratbagd: Ratbagd, args: argparse.Namespace) -> None:
resolution, profile, device = find_resolution(ratbagd, args)
print_resolution(device, profile, resolution, 0)
@@ -855,6 +891,14 @@ parser_def: List[RatbagParserSchemaElement] = [
of_type: link,
dest: "rate",
},
{
of_type: link,
dest: "angle_snapping",
},
{
of_type: link,
dest: "debounce",
},
{
of_type: link,
dest: "button",
@@ -1067,6 +1111,76 @@ Rate commands work on the given profile, or on the active profile if none is giv
},
],
},
{
of_type: switch,
name: "angle_snapping",
help_str: """Angle snapping information
Angle snapping commands work on the given profile, or on the active profile if none is given.""",
tag: "angle_snapping",
group: "AngleSnapping",
switch: [
{
of_type: command,
name: "get",
help_str: "Show current angle snapping",
func: func_angle_snapping_get,
},
{
of_type: command,
name: "set",
help_str: "Set the current angle snapping to N",
pos_args: [
{
of_type: argument,
name: "angle_snapping_n",
metavar: "N",
help_str: "The angle snapping to set as current",
arg_type: int,
},
],
func: func_angle_snapping_set,
},
],
},
{
of_type: switch,
name: "debounce",
help_str: """Access debounce time information
Debounce commands work on the given profile, or on the active profile if none is given.""",
tag: "debounce",
group: "Debounce",
switch: [
{
of_type: command,
name: "get",
help_str: "Show current debounce time",
func: func_debounce_get,
},
{
of_type: command,
name: "get-all",
help_str: "Show all available debounce times",
func: func_debounce_get_all,
},
{
of_type: command,
name: "set",
help_str: "Set the current debounce time to N",
pos_args: [
{
of_type: argument,
name: "debounce_n",
metavar: "N",
help_str: "The debounce time to set as current",
arg_type: int,
},
],
func: func_debounce_set,
},
],
},
{
of_type: switch,
name: "button",

View File

@@ -543,6 +543,37 @@ class RatbagdProfile(_RatbagdDBus):
"""The list of supported report rates"""
return self._get_dbus_property("ReportRates") or []
@GObject.Property
def angle_snapping(self):
"""The angle snapping option."""
return self._get_dbus_property("AngleSnapping")
@angle_snapping.setter
def angle_snapping(self, value):
"""Set the angle snapping option.
@param value The angle snapping option as int
"""
self._set_dbus_property("AngleSnapping", "i", value)
@GObject.Property
def debounce(self):
"""The button debounce time in ms."""
return self._get_dbus_property("Debounce")
@debounce.setter
def debounce(self, value):
"""Set the button debounce time in ms.
@param value The button debounce time, as int
"""
self._set_dbus_property("Debounce", "i", value)
@GObject.Property
def debounces(self):
"""The list of supported debounce times"""
return self._get_dbus_property("Debounces") or []
@GObject.Property
def resolutions(self):
"""A list of RatbagdResolution objects with this profile's resolutions.