From: Peter Hutterer Date: Wed, 12 Jun 2024 23:00:21 +0000 (+1000) Subject: Add tablet area configuration X-Git-Tag: 1.27.0~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cf5b7bee01adf3877f7d9acb0888343eec30d2f9;p=platform%2Fupstream%2Flibinput.git Add tablet area configuration This adds the configuration option to define a rectangle that serves as an input area on external tablets such as an Intuos. The intention behind this is to make this input area behave as if it was the only physical input area on this tablet with libinput emulating proximity events as required for where the tools moves in and out of this area. This could also be achieved with the existing calibration setting but area configuration is not calibration and we don't want to expose other side-effects of the matrix (e.g. scaling and rotation) for these devices. Part-of: --- diff --git a/completion/zsh/_libinput b/completion/zsh/_libinput index 58428b36..df14ab59 100644 --- a/completion/zsh/_libinput +++ b/completion/zsh/_libinput @@ -49,6 +49,7 @@ __all_seats() '--udev=[Listen for notifications on the given seat]:seat:__all_seats' \ '--apply-to=[Apply configuration options where the device name matches the pattern]:pattern' \ '--disable-sendevents=[Disable send-events option for the devices matching the pattern]:pattern' \ + '--set-area=[Set the desired area as "x1/y1 x2/y2" (within [0.0, 1.0]) ]' \ '--set-click-method=[Set the desired click method]:click-method:(none clickfinger buttonareas)' \ '--set-clickfinger-map=[Set button mapping for clickfinger]:tap-map:(( \ lrm\:2-fingers\ right-click\ /\ 3-fingers\ middle-click \ diff --git a/doc/user/configuration.rst b/doc/user/configuration.rst index e9260a3b..3b00767b 100644 --- a/doc/user/configuration.rst +++ b/doc/user/configuration.rst @@ -191,3 +191,16 @@ the given threshold is met, and will reach the maximum logical pressure before the maximum hardware-supported pressure is reached. See :ref:`tablet-pressure-range` for more info. + +------------------------------------------------------------------------------ +Area configuration +------------------------------------------------------------------------------ + +Area configuration is available for some indirect input devices such as +graphics tablets. This configuration allows reducing the active area of +such a device to a subset of the physically possible area. + +An example use-case for this is to match the aspect ratio of the device to that +of the screen. + +See :ref:`tablet-area` for more info. diff --git a/doc/user/meson.build b/doc/user/meson.build index 4609eb65..49ef2d50 100644 --- a/doc/user/meson.build +++ b/doc/user/meson.build @@ -120,6 +120,7 @@ src_rst = files( 'svg/software-buttons-thumbpress.svg', 'svg/software-buttons-visualized.svg', 'svg/swipe-gestures.svg', + 'svg/tablet-area.svg', 'svg/tablet-axes.svg', 'svg/tablet-cintiq24hd-modes.svg', 'svg/tablet-interfaces.svg', diff --git a/doc/user/svg/tablet-area.svg b/doc/user/svg/tablet-area.svg new file mode 100644 index 00000000..b83890f6 --- /dev/null +++ b/doc/user/svg/tablet-area.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + 0/0 + + + + + + + + + + + diff --git a/doc/user/tablet-support.rst b/doc/user/tablet-support.rst index fededac0..5182a496 100644 --- a/doc/user/tablet-support.rst +++ b/doc/user/tablet-support.rst @@ -467,3 +467,31 @@ devices arbitration has to be done in userspace. libinput uses the **libinput_device_group** to decide on touch arbitration and automatically discards touch events whenever a tool is in proximity. The exact behavior is device-dependent. + +.. _tablet-area: + +------------------------------------------------------------------------------ +Tablet area +------------------------------------------------------------------------------ + +External tablet devices such as e.g. the Wacom Intuos series can be configured +to reduce the available logical input area. Typically the logical input area +is equivalent to the physical input area but it can be reduced with the +**libinput_device_config_area_set_rectangle()** call. Once reduced, input +events outside the logical input area are ignored and the logical input area +acts as if it represented the extents of the physical tablet. + +.. figure:: tablet-area.svg + :align: center + + Tablet area configuration example + +In the image above, the area is set to the rectangle 0.25/0.25 to 0.5/0.75. +Even though the tool is roughly at the physical position ``0.5 * width`` and +``0.75 * height``, the return values of +**libinput_event_tablet_tool_get_x_transformed()** and +**libinput_event_tablet_tool_get_y_transformed()** would be close to the +maximum provided in this call. + +The size of the tablet reported by **libinput_device_get_size()** always reflects +the physical area, not the logical area. diff --git a/src/libinput-private.h b/src/libinput-private.h index dd526cb0..6a0267f9 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -228,6 +228,14 @@ struct libinput_device_config_calibration { float matrix[6]); }; +struct libinput_device_config_area { + int (*has_rectangle)(struct libinput_device *device); + enum libinput_config_status (*set_rectangle)(struct libinput_device *device, + const struct libinput_config_area_rectangle *rectangle); + struct libinput_config_area_rectangle (*get_rectangle)(struct libinput_device *device); + struct libinput_config_area_rectangle (*get_default_rectangle)(struct libinput_device *device); +}; + struct libinput_device_config_send_events { uint32_t (*get_modes)(struct libinput_device *device); enum libinput_config_status (*set_mode)(struct libinput_device *device, @@ -391,6 +399,7 @@ struct libinput_device_config_gesture { struct libinput_device_config { struct libinput_device_config_tap *tap; struct libinput_device_config_calibration *calibration; + struct libinput_device_config_area *area; struct libinput_device_config_send_events *sendevents; struct libinput_device_config_accel *accel; struct libinput_device_config_natural_scroll *natural_scroll; diff --git a/src/libinput.c b/src/libinput.c index 9f686345..7bf26c7d 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -4134,6 +4134,45 @@ libinput_device_config_calibration_get_default_matrix(struct libinput_device *de return device->config.calibration->get_default_matrix(device, matrix); } +LIBINPUT_EXPORT int +libinput_device_config_area_has_rectangle(struct libinput_device *device) +{ + return device->config.area ? + device->config.area->has_rectangle(device) : 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_area_set_rectangle(struct libinput_device *device, + const struct libinput_config_area_rectangle *rectangle) +{ + if (!libinput_device_config_area_has_rectangle(device)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.area->set_rectangle(device, rectangle); +} + +LIBINPUT_EXPORT struct libinput_config_area_rectangle +libinput_device_config_area_get_rectangle(struct libinput_device *device) +{ + struct libinput_config_area_rectangle rect = { 0.0, 0.0, 1.0, 1.0 }; + + if (!libinput_device_config_area_has_rectangle(device)) + return rect; + + return device->config.area->get_rectangle(device); +} + +LIBINPUT_EXPORT struct libinput_config_area_rectangle +libinput_device_config_area_get_default_rectangle(struct libinput_device *device) +{ + struct libinput_config_area_rectangle rect = { 0.0, 0.0, 1.0, 1.0 }; + + if (!libinput_device_config_area_has_rectangle(device)) + return rect; + + return device->config.area->get_default_rectangle(device); +} + LIBINPUT_EXPORT uint32_t libinput_device_config_send_events_get_modes(struct libinput_device *device) { diff --git a/src/libinput.h b/src/libinput.h index aa0f2be3..2e4cfb85 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -2401,6 +2401,10 @@ libinput_event_tablet_tool_wheel_has_changed( * libinput_event_tablet_tool_get_x_transformed() for transforming the axis * value into a different coordinate space. * + * If an area is defined for this device, the coordinate is in mm from + * the top left corner of the area. See + * libinput_device_config_area_set_rectangle() for details. + * * @note On some devices, returned value may be negative or larger than the * width of the device. See the libinput documentation for more details. * @@ -2420,6 +2424,10 @@ libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event); * libinput_event_tablet_tool_get_y_transformed() for transforming the axis * value into a different coordinate space. * + * If an area is defined for this device, the coordinate is in mm from + * the top left corner of the area. See + * libinput_device_config_area_set_rectangle() for details. + * * @note On some devices, returned value may be negative or larger than the * width of the device. See the libinput documentation for more details. * @@ -5128,6 +5136,143 @@ int libinput_device_config_calibration_get_default_matrix(struct libinput_device *device, float matrix[6]); +/** + * @ingroup config + * + * Describes a rectangle to configure a device's area, see + * libinput_device_config_area_set_rectangle(). + * + * This struct describes a rectangle via the upper left points (x1, y1) + * and the lower right point (x2, y2). + * + * All arguments are normalized to the range [0.0, 1.0] to represent the + * corresponding proportion of the device's width and height, respectively. + * A rectangle covering the whole device thus comprises of the points + * (0.0, 0.0) and (1.0, 1.0). + * + * The conditions x1 < x2 and y1 < y2 must be true. + */ +struct libinput_config_area_rectangle { + double x1; + double y1; + double x2; + double y2; +}; + +/** + * @ingroup config + * + * Check if the device can change its logical input area via a rectangle. + * + * @param device The device to check + * @return Non-zero if the device can be calibrated, zero otherwise. + * + * @see libinput_device_config_area_set_rectangle + * @see libinput_device_config_area_get_rectangle + * @see libinput_device_config_area_get_default_rectangle + */ +int +libinput_device_config_area_has_rectangle(struct libinput_device *device); + +/** + * @ingroup config + * + * Set the given rectangle as the logical input area of this device. + * Future interactions by a tablet tool on this devices are scaled + * to only consider events within this logical input area - as if the + * logical input area were the available physical area. + * + * The coordinates of the rectangle represent the proportion of the + * available maximum physical area, normalized to the range [0.0, 1.0]. + * For example, a rectangle with the two points 0.25, 0.5, 0.75, 1.0 + * adds a 25% dead zone to the left and right and a 50% dead zone on + * the top: + * + * @code + * +----------------------------------+ + * | | + * | 50% | + * | | + * | +-----------------+ | + * | | | | + * | 25% | | 25% | + * | | | | + * +--------+-----------------+-------+ + * @endcode + * + * The area applies in the tablet's current logical rotation, i.e. the above + * example is always at the bottom of the tablet. + * + * Once applied, the logical area's top-left coordinate (in the current logical + * rotation) becomes the new offset (0/0) and the return values of + * libinput_event_tablet_tool_get_x() and libinput_event_tablet_tool_get_y() + * are in relation to this new offset. + * + * Likewise, libinput_event_tablet_tool_get_x_transformed() and + * libinput_event_tablet_tool_get_y_transformed() represent the value scaled + * into the configured logical area. + * + * The return value of libinput_device_get_size() is not affected by the + * configured area. + * + * Changing the area may not take effect immediately, the device may wait until + * it is in a neutral state before applying any changes. + * + * @param device The device to check + * @param rect The intended rectangle + * @return A config status code. Setting the area on a device that does not + * support area rectangles always fails with @ref LIBINPUT_CONFIG_STATUS_UNSUPPORTED. + * + * @see libinput_device_config_area_has_rectangle + * @see libinput_device_config_area_get_rectangle + * @see libinput_device_config_area_get_default_rectangle + */ +enum libinput_config_status +libinput_device_config_area_set_rectangle(struct libinput_device *device, + const struct libinput_config_area_rectangle *rect); + +/** + * @ingroup config + * + * Return the current area rectangle for this device. + * + * The return value for a device that does not support area rectangles is a + * rectangle with the points 0/0 and 1/1. + * + * @note It is an application bug to call this function for devices where + * libinput_device_config_area_has_rectangle() returns 0. + * + * @param device The device to check + * @return The current area rectangle + * + * @see libinput_device_config_area_has_rectangle + * @see libinput_device_config_area_set_rectangle + * @see libinput_device_config_area_get_default_rectangle + */ +struct libinput_config_area_rectangle +libinput_device_config_area_get_rectangle(struct libinput_device *device); + +/** + * @ingroup config + * + * Return the default area rectangle for this device. + * + * The return value for a device that does not support area rectangles is a + * rectangle with the points 0/0 and 1/1. + * + * @note It is an application bug to call this function for devices where + * libinput_device_config_area_has_rectangle() returns 0. + * + * @param device The device to check + * @return The default area rectangle + * + * @see libinput_device_config_area_has_rectangle + * @see libinput_device_config_area_set_rectangle + * @see libinput_device_config_area_get_rectangle + */ +struct libinput_config_area_rectangle +libinput_device_config_area_get_default_rectangle(struct libinput_device *device); + /** * @ingroup config * diff --git a/src/libinput.sym b/src/libinput.sym index e8275d50..2f3a7eee 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -350,3 +350,10 @@ LIBINPUT_1.26 { libinput_tablet_tool_config_pressure_range_get_default_minimum; libinput_tablet_tool_config_pressure_range_get_default_maximum; } LIBINPUT_1.23; + +LIBINPUT_1.27 { + libinput_device_config_area_has_rectangle; + libinput_device_config_area_set_rectangle; + libinput_device_config_area_get_rectangle; + libinput_device_config_area_get_default_rectangle; +} LIBINPUT_1.26; diff --git a/tools/libinput-debug-events.man b/tools/libinput-debug-events.man index 15437694..100e39a5 100644 --- a/tools/libinput-debug-events.man +++ b/tools/libinput-debug-events.man @@ -87,6 +87,10 @@ Enable or disable the scroll button lock .B \-\-enable\-tap|\-\-disable\-tap Enable or disable tap-to-click .TP 8 +.B \-\-set\-area="x1/y1 x2/y2" +Set the tablet area to the rectangle described by the two points x1/y1 and x2/y2. All +coordinates must be in the range [0.0, 1.0]. +.TP 8 .B \-\-set\-calibration="1.0 0.0 0.0 0.0 1.0 0.0" Set the first 6 elements of a 3x3 matrix to use for calibration. The third row of the matrix is always "0.0 0.0 0.1". diff --git a/tools/shared.c b/tools/shared.c index 9df277d6..327005ed 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -133,6 +133,10 @@ tools_init_options(struct tools_options *options) options->pressure_range[1] = 1.0; options->calibration[0] = 1.0; options->calibration[4] = 1.0; + options->area.x1 = 0.0; + options->area.y1 = 0.0; + options->area.x2 = 1.0; + options->area.y2 = 1.0; } int @@ -390,6 +394,22 @@ tools_parse_option(int option, options->calibration[i] = matrix[i]; free(matrix); break; + } + case OPT_AREA: { + if (!optarg) + return 1; + + double x1, x2, y1, y2; + + if (sscanf(optarg, "%lf/%lf %lf/%lf", &x1, &y1, &x2, &y2) != 4) { + fprintf(stderr, "Invalid --set-area values\n"); + return 1; + } + options->area.x1 = x1; + options->area.y1 = y1; + options->area.x2 = x2; + options->area.y2 = y2; + break; } } return 0; @@ -606,6 +626,9 @@ tools_device_apply_config(struct libinput_device *device, if (libinput_device_config_calibration_has_matrix(device)) libinput_device_config_calibration_set_matrix(device, options->calibration); + + if (libinput_device_config_area_has_rectangle(device)) + libinput_device_config_area_set_rectangle(device, &options->area); } void diff --git a/tools/shared.h b/tools/shared.h index 922ace06..cadb36e3 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -68,6 +68,7 @@ enum configuration_options { OPT_ROTATION_ANGLE, OPT_PRESSURE_RANGE, OPT_CALIBRATION, + OPT_AREA, }; #define CONFIGURATION_OPTIONS \ @@ -103,7 +104,8 @@ enum configuration_options { { "set-custom-type", required_argument, 0, OPT_CUSTOM_TYPE },\ { "set-rotation-angle", required_argument, 0, OPT_ROTATION_ANGLE }, \ { "set-pressure-range", required_argument, 0, OPT_PRESSURE_RANGE }, \ - { "set-calibration", required_argument, 0, OPT_CALIBRATION } + { "set-calibration", required_argument, 0, OPT_CALIBRATION }, \ + { "set-area", required_argument, 0, OPT_AREA } enum tools_backend { BACKEND_NONE, @@ -138,6 +140,7 @@ struct tools_options { unsigned int angle; double pressure_range[2]; float calibration[6]; + struct libinput_config_area_rectangle area; }; void tools_init_options(struct tools_options *options);