Add tablet area configuration
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 12 Jun 2024 23:00:21 +0000 (09:00 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Tue, 5 Nov 2024 02:10:48 +0000 (12:10 +1000)
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: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1013>

12 files changed:
completion/zsh/_libinput
doc/user/configuration.rst
doc/user/meson.build
doc/user/svg/tablet-area.svg [new file with mode: 0644]
doc/user/tablet-support.rst
src/libinput-private.h
src/libinput.c
src/libinput.h
src/libinput.sym
tools/libinput-debug-events.man
tools/shared.c
tools/shared.h

index 58428b368cece09c0b83acf45ab951a43644d08d..df14ab59ccd2fb72d6a694c96925335878774d3a 100644 (file)
@@ -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 \
index e9260a3b9598ba30b9707150ed8c6e71cd8dabef..3b00767b1f6d6b77b65ad5cb236f052e04353fb5 100644 (file)
@@ -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.
index 4609eb656c2d3dec9168a1b5d321ec8d744a4a8f..49ef2d504dbc0a2773f5eceba80db93ac1057178 100644 (file)
@@ -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 (file)
index 0000000..b83890f
--- /dev/null
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="229.5488mm"
+   height="86.66362mm"
+   viewBox="0 0 813.36188 307.07582"
+   id="svg2"
+   version="1.1"
+   inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
+   sodipodi:docname="tablet-area.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4294"
+       id="linearGradient4300"
+       x1="465.81339"
+       y1="666.13727"
+       x2="454.82117"
+       y2="658.65521"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4294">
+      <stop
+         style="stop-color:#1a1a1a;stop-opacity:1;"
+         offset="0"
+         id="stop4296" />
+      <stop
+         style="stop-color:#808080;stop-opacity:1"
+         offset="1"
+         id="stop4298" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="410.53571"
+     inkscape:cy="188.39286"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer3"
+     showgrid="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-width="3072"
+     inkscape:window-height="1659"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:showpageshadow="2"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="tablet"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline"
+     transform="translate(67.109152,-133.63374)">
+    <g
+       id="g4309"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90"
+       transform="translate(0,1.0715222)">
+      <rect
+         y="134.15933"
+         x="75.787216"
+         height="306.02466"
+         width="522.19733"
+         id="rect4136"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:1.05118;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:4.20473, 1.05118;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.748138;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.99255, 0.748138;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect4140"
+         width="357.34042"
+         height="226.52563"
+         x="199.33878"
+         y="175.42407" />
+      <rect
+         y="175.72914"
+         x="103.10225"
+         height="22.142857"
+         width="65"
+         id="rect4142"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect4148"
+         width="65"
+         height="22.142857"
+         x="103.10225"
+         y="203.72914" />
+      <rect
+         y="231.72913"
+         x="103.10225"
+         height="22.142857"
+         width="65"
+         id="rect4150"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         y="323.72913"
+         x="103.10225"
+         height="22.142857"
+         width="65"
+         id="rect4154"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+      <rect
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1"
+         id="rect4156"
+         width="65"
+         height="22.142857"
+         x="103.10225"
+         y="351.72913" />
+      <circle
+         r="22.98097"
+         cy="287.06125"
+         cx="135.61298"
+         id="path4158"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+      <ellipse
+         ry="12.608653"
+         rx="11.5985"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.520431;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:2.08172, 0.520431;stroke-dashoffset:0;stroke-opacity:1"
+         id="circle4160"
+         cx="135.61298"
+         cy="287.06125" />
+      <rect
+         y="379.72913"
+         x="103.10225"
+         height="22.142857"
+         width="65"
+         id="rect4162"
+         style="opacity:0.92;fill:#4d4d4d;fill-opacity:1;stroke:#4d4d4d;stroke-width:0.989;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:3.956, 0.989;stroke-dashoffset:0;stroke-opacity:1" />
+    </g>
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="area">
+    <rect
+       style="display:inline;fill:#a44d4d;fill-opacity:1;stroke:none;stroke-width:0.675728"
+       id="rect1"
+       width="131.51813"
+       height="126.57689"
+       x="326.15009"
+       y="97.775696" />
+    <text
+       xml:space="preserve"
+       style="display:inline;font-size:11.25px;fill:#a44d4d;fill-opacity:1;stroke:none;stroke-width:0.9375"
+       x="261.92404"
+       y="244.01244"
+       id="text1"
+       transform="translate(67.109152,-133.63374)"><tspan
+         sodipodi:role="line"
+         id="tspan1"
+         style="fill:#000000;stroke-width:0.9375"
+         x="261.92404"
+         y="244.01244">0/0</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.9375;stroke-linecap:round;stroke-dasharray:none"
+       d="m 259.17629,227.63135 v 7.63349"
+       id="path1"
+       transform="translate(67.109152,-133.63374)" />
+    <path
+       style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.9375;stroke-linecap:round;stroke-dasharray:none"
+       d="m 262.99304,231.44809 h -7.63349"
+       id="path2"
+       transform="translate(67.109152,-133.63374)" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="stylus"
+     style="display:inline"
+     transform="translate(67.109152,-133.63374)">
+    <g
+       id="g4304"
+       transform="matrix(0.37129971,0.09948946,-0.09618892,0.35898192,319.19555,24.123239)"
+       style="display:inline">
+      <path
+         sodipodi:nodetypes="czcc"
+         inkscape:connector-curvature="0"
+         id="path4286"
+         d="m 387.83544,799.76093 c -1.1128,3.61694 -3.2211,13.05163 -1.08543,14.07769 2.13567,1.02606 7.81039,-3.72162 10.99756,-6.69095 z"
+         style="display:inline;fill:#cccccc;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ssssccssscsssssssssssssssssss"
+         inkscape:connector-curvature="0"
+         id="path4283"
+         d="m 392.64431,804.79039 c -8.52094,-5.90399 -8.49394,-11.01546 0.22879,-43.30647 1.03999,-3.85 2.46829,-9.67602 3.17399,-12.9467 0.99731,-4.62219 2.39455,-7.29497 6.27321,-12 2.74456,-3.32932 5.25157,-6.2783 5.57113,-6.5533 40.78433,-60.97488 80.48307,-125.1652 118.27253,-184 9.86283,-15.675 26.59424,-42.225 37.18089,-59 10.58666,-16.775 34.01422,-53.9 52.06125,-82.5 18.04703,-28.6 35.04505,-55.31677 37.77338,-59.37059 l 4.9606,-7.3706 4.1828,0.57332 c 4.16371,0.5707 4.19706,0.54958 7.30887,-4.62941 3.75631,-6.2516 8.82067,-11.57582 12.2516,-12.88026 5.99391,-2.27888 14.03303,2.9506 14.03303,9.12854 0,3.90203 -2.51704,10.62127 -6.02878,16.09385 -1.63417,2.54664 -2.97122,4.85949 -2.97122,5.13969 0,0.28019 0.9,1.54715 2,2.81546 2.28453,2.63408 2.47267,4.21918 0.86833,7.31574 -1.28218,2.47476 -26.61383,45.18798 -55.85724,94.18426 -10.83283,18.15 -25.72943,43.1137 -33.10357,55.47489 -7.37413,12.3612 -13.69273,23.17153 -14.04131,24.02297 -0.34859,0.85144 -7.50972,12.78774 -15.91363,26.52511 -15.54138,25.40455 -32.24417,52.9052 -70.74345,116.47703 -40.26028,66.47968 -43.66308,72.46026 -49.21634,86.5 -1.74036,4.4 -3.92035,8.675 -4.8444,9.5 -0.92405,0.825 -4.36246,3.75 -7.6409,6.5 -3.27845,2.75 -9.57132,8.3067 -13.98415,12.34823 -10.62726,9.73304 -16.99729,13.87361 -22.52334,14.64034 -3.99187,0.55386 -5.03885,0.251 -9.27207,-2.6821 z"
+         style="display:inline;fill:#000000" />
+      <path
+         sodipodi:nodetypes="scccs"
+         inkscape:connector-curvature="0"
+         id="path4292"
+         d="m 450.89044,688.88586 c 8.71518,5.62513 45.74035,-59.18436 43.57923,-75.43494 l -7.07107,-6.56599 c -29.93081,25.86352 -47.78438,74.72281 -47.78438,74.72281 z"
+         style="fill:url(#linearGradient4300);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
index fededac050b28873eb08e2a2d0a705a1a1580839..5182a4963d695e17c1b022441e9cbdacc1456102 100644 (file)
@@ -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.
index dd526cb0756b4d2ef87595393d53473b4db92f37..6a0267f9aabd849b496c99cdfe143371588bdc07 100644 (file)
@@ -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;
index 9f68634599c09604808eed470d93b71174a53ae2..7bf26c7dfdc2c86047c86bb23f92d8b3243168d6 100644 (file)
@@ -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)
 {
index aa0f2be3a3580988a5ed4ff991f80afe8b971427..2e4cfb850470fa5298d0f049b94fbb6ce6ad17f0 100644 (file)
@@ -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
  *
index e8275d50f55aa1aae5253bf645fdf7e42edc3d93..2f3a7eee11056b5e68bd26f9f28fa997784482b0 100644 (file)
@@ -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;
index 15437694469d90a6e28506756158d0798bc422ef..100e39a5fe42ec5cd0d5ce9656920e6146184982 100644 (file)
@@ -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".
index 9df277d676f755c059ef7c7f2e8df0e2cd155d3b..327005ede050b43172635ecc736cb37e936620c6 100644 (file)
@@ -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
index 922ace060fb30f00bb6dc515e41133300fd36b79..cadb36e3e4186c81688b7fefec65715683e115ad 100644 (file)
@@ -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);