• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2006-2009 Simon Thum
3  * Copyright © 2012 Jonas Ådahl
4  * Copyright © 2014-2015 Red Hat, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 
33 #include "filter.h"
34 #include "libinput-util.h"
35 #include "filter-private.h"
36 
37 struct tablet_accelerator_flat {
38 	struct motion_filter base;
39 
40 	double factor;
41 	int xres, yres;
42 	double xres_scale, /* 1000dpi : tablet res */
43 	       yres_scale; /* 1000dpi : tablet res */
44 };
45 
46 static inline struct normalized_coords
tablet_accelerator_filter_flat_mouse(struct tablet_accelerator_flat * filter,const struct device_float_coords * units)47 tablet_accelerator_filter_flat_mouse(struct tablet_accelerator_flat *filter,
48 				     const struct device_float_coords *units)
49 {
50 	struct normalized_coords accelerated;
51 
52 	/*
53 	   Tablets are high res (Intuos 4 is 5080 dpi) and unmodified deltas
54 	   are way too high. Slow it down to the equivalent of a 1000dpi
55 	   mouse. The ratio of that is:
56 		ratio = 1000/(resolution_per_mm * 25.4)
57 
58 	   i.e. on the Intuos4 it's a ratio of ~1/5.
59 	 */
60 
61 	accelerated.x = units->x * filter->xres_scale;
62 	accelerated.y = units->y * filter->yres_scale;
63 
64 	accelerated.x *= filter->factor;
65 	accelerated.y *= filter->factor;
66 
67 	return accelerated;
68 }
69 
70 static struct normalized_coords
tablet_accelerator_filter_flat_pen(struct tablet_accelerator_flat * filter,const struct device_float_coords * units)71 tablet_accelerator_filter_flat_pen(struct tablet_accelerator_flat *filter,
72 				   const struct device_float_coords *units)
73 {
74 	struct normalized_coords accelerated;
75 
76 	/* Tablet input is in device units, output is supposed to be in
77 	 * logical pixels roughly equivalent to a mouse/touchpad.
78 	 *
79 	 * This is a magical constant found by trial and error. On a 96dpi
80 	 * screen 0.4mm of movement correspond to 1px logical pixel which
81 	 * is almost identical to the tablet mapped to screen in absolute
82 	 * mode. Tested on a Intuos5, other tablets may vary.
83 	 */
84        const double DPI_CONVERSION = 96.0/25.4 * 2.5; /* unitless factor */
85        struct normalized_coords mm;
86 
87        mm.x = 1.0 * units->x/filter->xres;
88        mm.y = 1.0 * units->y/filter->yres;
89        accelerated.x = mm.x * filter->factor * DPI_CONVERSION;
90        accelerated.y = mm.y * filter->factor * DPI_CONVERSION;
91 
92        return accelerated;
93 }
94 
95 static struct normalized_coords
tablet_accelerator_filter_flat(struct motion_filter * filter,const struct device_float_coords * units,void * data,uint64_t time)96 tablet_accelerator_filter_flat(struct motion_filter *filter,
97 			       const struct device_float_coords *units,
98 			       void *data, uint64_t time)
99 {
100 	struct tablet_accelerator_flat *accel_filter =
101 		(struct tablet_accelerator_flat *)filter;
102 	struct libinput_tablet_tool *tool = (struct libinput_tablet_tool*)data;
103 	enum libinput_tablet_tool_type type;
104 	struct normalized_coords accel;
105 
106 	type = libinput_tablet_tool_get_type(tool);
107 
108 	switch (type) {
109 	case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
110 	case LIBINPUT_TABLET_TOOL_TYPE_LENS:
111 		accel = tablet_accelerator_filter_flat_mouse(accel_filter,
112 							     units);
113 		break;
114 	default:
115 		accel = tablet_accelerator_filter_flat_pen(accel_filter,
116 							   units);
117 		break;
118 	}
119 
120 	return accel;
121 }
122 
123 static bool
tablet_accelerator_set_speed(struct motion_filter * filter,double speed_adjustment)124 tablet_accelerator_set_speed(struct motion_filter *filter,
125 			     double speed_adjustment)
126 {
127 	struct tablet_accelerator_flat *accel_filter =
128 		(struct tablet_accelerator_flat *)filter;
129 
130 	assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
131 
132 	accel_filter->factor = speed_adjustment + 1.0;
133 
134 	return true;
135 }
136 
137 static void
tablet_accelerator_destroy(struct motion_filter * filter)138 tablet_accelerator_destroy(struct motion_filter *filter)
139 {
140 	struct tablet_accelerator_flat *accel_filter =
141 		(struct tablet_accelerator_flat *)filter;
142 
143 	free(accel_filter);
144 }
145 
146 struct motion_filter_interface accelerator_interface_tablet = {
147 	.type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
148 	.filter = tablet_accelerator_filter_flat,
149 	.filter_constant = NULL,
150 	.restart = NULL,
151 	.destroy = tablet_accelerator_destroy,
152 	.set_speed = tablet_accelerator_set_speed,
153 };
154 
155 static struct tablet_accelerator_flat *
create_tablet_filter_flat(int xres,int yres)156 create_tablet_filter_flat(int xres, int yres)
157 {
158 	struct tablet_accelerator_flat *filter;
159 
160 	filter = zalloc(sizeof *filter);
161 	filter->factor = 1.0;
162 	filter->xres = xres;
163 	filter->yres = yres;
164 	filter->xres_scale = DEFAULT_MOUSE_DPI/(25.4 * xres);
165 	filter->yres_scale = DEFAULT_MOUSE_DPI/(25.4 * yres);
166 
167 	return filter;
168 }
169 
170 struct motion_filter *
create_pointer_accelerator_filter_tablet(int xres,int yres)171 create_pointer_accelerator_filter_tablet(int xres, int yres)
172 {
173 	struct tablet_accelerator_flat *filter;
174 
175 	filter = create_tablet_filter_flat(xres, yres);
176 	if (!filter)
177 		return NULL;
178 
179 	filter->base.interface = &accelerator_interface_tablet;
180 
181 	return &filter->base;
182 }
183