forked from drath/libratbag
Implement set profile resolution dpi
Works only in Logitech with adjustable DPI for now (MX Master). Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
@@ -354,6 +354,12 @@ etekcity_write_button(struct ratbag_button *button)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
etekcity_write_resolution_dpi(struct ratbag_profile *profile, int dpi)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
etekcity_probe(struct ratbag_device *device, const struct ratbag_id id)
|
||||
{
|
||||
@@ -439,4 +445,5 @@ struct ratbag_driver etekcity_driver = {
|
||||
.has_capability = etekcity_has_capability,
|
||||
.read_button = etekcity_read_button,
|
||||
.write_button = etekcity_write_button,
|
||||
.write_resolution_dpi = etekcity_write_resolution_dpi,
|
||||
};
|
||||
|
||||
@@ -73,6 +73,18 @@ hidpp20drv_write_button(struct ratbag_button *button)
|
||||
static int
|
||||
hidpp20drv_has_capability(const struct ratbag_device *device, enum ratbag_capability cap)
|
||||
{
|
||||
/*
|
||||
* We need to force the non const, but we will not change anything,
|
||||
* promise!
|
||||
*/
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data((struct ratbag_device *)device);
|
||||
|
||||
switch (cap) {
|
||||
case RATBAG_CAP_SWITCHABLE_RESOLUTION:
|
||||
return !!(drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -85,7 +97,7 @@ hidpp20drv_current_profile(struct ratbag_device *device)
|
||||
static int
|
||||
hidpp20drv_set_current_profile(struct ratbag_device *device, unsigned int index)
|
||||
{
|
||||
return -1;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -136,6 +148,58 @@ hidpp20drv_read_resolution_dpi(struct ratbag_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20drv_write_resolution_dpi(struct ratbag_profile *profile, int dpi)
|
||||
{
|
||||
struct ratbag_device *device = profile->device;
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
struct hidpp20drv_data *drv_data = ratbag_get_drv_data(device);
|
||||
struct hidpp20_sensor *sensors, *sensor;
|
||||
int rc, i;
|
||||
|
||||
if (!(drv_data->capabilities & HIDPP_CAP_SWITCHABLE_RESOLUTION_2201))
|
||||
return -ENOTSUP;
|
||||
|
||||
rc = hidpp20_adjustable_dpi_get_sensors(device, &sensors);
|
||||
if (rc < 0) {
|
||||
log_error(ratbag,
|
||||
"Error while requesting resolution: %s (%d)\n",
|
||||
strerror(-rc), rc);
|
||||
return 0;
|
||||
} else if (rc == 0) {
|
||||
log_error(ratbag, "Error, no compatible sensors found.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* just for clarity, we use the first available sensor only */
|
||||
sensor = &sensors[0];
|
||||
|
||||
/* validate that the sensor accepts the given DPI */
|
||||
rc = -EINVAL;
|
||||
if (dpi < sensor->dpi_min || dpi > sensor->dpi_max)
|
||||
goto out;
|
||||
if (sensor->dpi_steps) {
|
||||
for (i = sensor->dpi_min; i < dpi; i += sensor->dpi_steps) {
|
||||
}
|
||||
if (i != dpi)
|
||||
goto out;
|
||||
} else {
|
||||
i = 0;
|
||||
while (sensor->dpi_list[i]) {
|
||||
if (sensor->dpi_list[i] == dpi)
|
||||
break;
|
||||
}
|
||||
if (sensor->dpi_list[i] != dpi)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = hidpp20_adjustable_dpi_set_sensor_dpi(device, sensor, dpi);
|
||||
|
||||
out:
|
||||
free(sensors);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_profile(struct ratbag_profile *profile, unsigned int index)
|
||||
{
|
||||
@@ -334,4 +398,5 @@ struct ratbag_driver hidpp20_driver = {
|
||||
.has_capability = hidpp20drv_has_capability,
|
||||
.read_button = hidpp20drv_read_button,
|
||||
.write_button = hidpp20drv_write_button,
|
||||
.write_resolution_dpi = hidpp20drv_write_resolution_dpi,
|
||||
};
|
||||
|
||||
@@ -578,6 +578,40 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int hidpp20_adjustable_dpi_set_sensor_dpi(struct ratbag_device *device,
|
||||
struct hidpp20_sensor *sensor, uint16_t dpi)
|
||||
{
|
||||
uint8_t feature_index, feature_type, feature_version;
|
||||
int rc;
|
||||
union hidpp20_message msg = {
|
||||
.msg.report_id = REPORT_ID_LONG,
|
||||
.msg.device_idx = 0xff,
|
||||
.msg.address = CMD_ADJUSTABLE_DPI_SET_SENSOR_DPI,
|
||||
.msg.parameters[0] = sensor->index,
|
||||
.msg.parameters[1] = dpi >> 8,
|
||||
.msg.parameters[2] = dpi & 0xff,
|
||||
};
|
||||
|
||||
rc = hidpp_root_get_feature(device,
|
||||
HIDPP_PAGE_ADJUSTABLE_DPI,
|
||||
&feature_index,
|
||||
&feature_type,
|
||||
&feature_version);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
msg.msg.sub_id = feature_index;
|
||||
|
||||
rc = hidpp20_request_command(device, &msg);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (hidpp20_get_unaligned_u16(&msg.msg.parameters[1]) != dpi)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1b04: Special keys and mouse buttons */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@@ -130,6 +130,13 @@ struct hidpp20_sensor {
|
||||
int hidpp20_adjustable_dpi_get_sensors(struct ratbag_device *device,
|
||||
struct hidpp20_sensor **sensors_list);
|
||||
|
||||
/**
|
||||
* set the current dpi of the provided sensor. sensor must have been
|
||||
* allocated by hidpp20_adjustable_dpi_get_sensors()
|
||||
*/
|
||||
int hidpp20_adjustable_dpi_set_sensor_dpi(struct ratbag_device *device,
|
||||
struct hidpp20_sensor *sensor, uint16_t dpi);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x1b04: Special keys and mouse buttons */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@@ -163,6 +163,13 @@ struct ratbag_driver {
|
||||
*/
|
||||
int (*write_button)(struct ratbag_button *button);
|
||||
|
||||
/** For the given profile, overwrite the current resolution
|
||||
* of the sensor expressed in DPI, and commit it to the hardware.
|
||||
*
|
||||
* Mandatory if the driver exports RATBAG_CAP_SWITCHABLE_RESOLUTION.
|
||||
*/
|
||||
int (*write_resolution_dpi)(struct ratbag_profile *profile, int dpi);
|
||||
|
||||
/* private */
|
||||
struct list link;
|
||||
};
|
||||
|
||||
@@ -607,6 +607,17 @@ ratbag_profile_get_resolution_dpi(const struct ratbag_profile *profile)
|
||||
return profile->current_dpi;
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_set_resolution_dpi(struct ratbag_profile *profile, int dpi)
|
||||
{
|
||||
if (!ratbag_device_has_capability(profile->device,
|
||||
RATBAG_CAP_SWITCHABLE_RESOLUTION))
|
||||
return -ENOTSUP;
|
||||
|
||||
assert(profile->device->driver->write_resolution_dpi);
|
||||
return profile->device->driver->write_resolution_dpi(profile, dpi);
|
||||
}
|
||||
|
||||
LIBRATBAG_EXPORT int
|
||||
ratbag_profile_get_report_rate_hz(const struct ratbag_profile *profile)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ global:
|
||||
ratbag_profile_get_button_by_index;
|
||||
ratbag_profile_get_report_rate_hz;
|
||||
ratbag_profile_get_resolution_dpi;
|
||||
ratbag_profile_set_resolution_dpi;
|
||||
ratbag_profile_ref;
|
||||
ratbag_profile_unref;
|
||||
ratbag_ref;
|
||||
|
||||
@@ -488,10 +488,71 @@ static const struct ratbag_cmd cmd_list = {
|
||||
.help = "List the available devices",
|
||||
};
|
||||
|
||||
static int
|
||||
ratbag_cmd_switch_dpi(struct ratbag *ratbag, uint32_t flags, int argc, char **argv)
|
||||
{
|
||||
const char *path;
|
||||
struct ratbag_device *device;
|
||||
struct ratbag_button *button_6, *button_7;
|
||||
struct ratbag_profile *profile = NULL;
|
||||
int rc = 1, commit = 0;
|
||||
int dpi;
|
||||
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
dpi = atoi(argv[0]);
|
||||
path = argv[1];
|
||||
|
||||
device = ratbag_cmd_open_device(ratbag, path);
|
||||
if (!device) {
|
||||
error("Looks like '%s' is not supported\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ratbag_device_has_capability(device,
|
||||
RATBAG_CAP_SWITCHABLE_RESOLUTION)) {
|
||||
error("Looks like '%s' has no switchable resolution\n", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
profile = ratbag_device_get_active_profile(device);
|
||||
if (!profile) {
|
||||
error("Huh hoh, something bad happened, unable to retrieve the active profile\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ratbag_profile_set_resolution_dpi(profile, dpi);
|
||||
if (!rc)
|
||||
printf("Switched the current resolution profile of '%s' to %d dpi\n",
|
||||
ratbag_device_get_name(device),
|
||||
dpi);
|
||||
else
|
||||
error("can't seem to be able to change the dpi: %s (%d)\n",
|
||||
strerror(-rc),
|
||||
rc);
|
||||
|
||||
out:
|
||||
profile = ratbag_profile_unref(profile);
|
||||
|
||||
device = ratbag_device_unref(device);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct ratbag_cmd cmd_switch_dpi = {
|
||||
.name = "switch-dpi",
|
||||
.cmd = ratbag_cmd_switch_dpi,
|
||||
.args = "N",
|
||||
.help = "Switch the resolution of the mouse in the active profile",
|
||||
};
|
||||
|
||||
static const struct ratbag_cmd *ratbag_commands[] = {
|
||||
&cmd_info,
|
||||
&cmd_switch_etekcity,
|
||||
&cmd_list,
|
||||
&cmd_switch_etekcity,
|
||||
&cmd_switch_dpi,
|
||||
&cmd_switch_profile,
|
||||
NULL,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user