1 /***************************************************************************
4 * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
5 * Copyright (C) 2011 Ryan Bourgeois <bluedragonx@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 **************************************************************************/
26 static int inline percentage(int dividend, int divisor)
28 return (double)dividend / (double)divisor * 100;
31 static int inline touch_range_ratio(const struct MConfig* cfg, int value)
33 return (double)(value - cfg->touch_min) / (double)(cfg->touch_max - cfg->touch_min) * 100;
36 /* Check if a finger is touching the trackpad.
38 static int is_touch(const struct MConfig* cfg,
39 const struct FingerState* hw)
41 if (cfg->touch_type == MCFG_SCALE)
42 return percentage(hw->touch_major, hw->width_major) > cfg->touch_down;
43 else if (cfg->touch_type == MCFG_SIZE)
44 return touch_range_ratio(cfg, hw->touch_major) > cfg->touch_down;
45 else if (cfg->touch_type == MCFG_PRESSURE)
46 return touch_range_ratio(cfg, hw->pressure) > cfg->touch_down;
51 /* Check if a finger is released from the touchpad.
53 static int is_release(const struct MConfig* cfg,
54 const struct FingerState* hw)
56 if (cfg->touch_type == MCFG_SCALE)
57 return percentage(hw->touch_major, hw->width_major) < cfg->touch_up;
58 else if (cfg->touch_type == MCFG_SIZE)
59 return touch_range_ratio(cfg, hw->touch_major) < cfg->touch_up;
60 else if (cfg->touch_type == MCFG_PRESSURE)
61 return touch_range_ratio(cfg, hw->pressure) < cfg->touch_up;
66 static int is_thumb(const struct MConfig* cfg,
67 const struct FingerState* hw)
69 if (!cfg->touch_minor)
72 int min = MINVAL(hw->touch_minor, hw->touch_major);
73 int max = MAXVAL(hw->touch_minor, hw->touch_major);
74 int pct = percentage(min, max);
75 int size = touch_range_ratio(cfg, hw->touch_major);
77 if (pct < cfg->thumb_ratio && size > cfg->thumb_size) {
79 xf86Msg(X_INFO, "is_thumb: yes %d > %d && %d > %d\n",
80 pct, cfg->thumb_ratio, size, cfg->thumb_size);
86 xf86Msg(X_INFO, "is_thumb: no %d > %d && %d > %d\n",
87 pct, cfg->thumb_ratio, size, cfg->thumb_size);
93 static int is_palm(const struct MConfig* cfg,
94 const struct FingerState* hw)
96 if (cfg->touch_type != MCFG_SCALE && cfg->touch_type != MCFG_SIZE)
99 int size = touch_range_ratio(cfg, hw->touch_major);
100 if (size > cfg->palm_size) {
102 xf86Msg(X_INFO, "is_palm: yes %d > %d\n", size, cfg->palm_size);
108 xf86Msg(X_INFO, "is_palm: no %d > %d\n", size, cfg->palm_size);
114 /* Find a touch by its tracking ID. Return -1 if not found.
116 static int find_touch(struct MTState* ms,
120 foreach_bit(i, ms->touch_used) {
121 if (ms->touch[i].tracking_id == tracking_id)
127 /* Add a touch to the MTState. Return the new index of the touch.
129 static int touch_append(struct MTState* ms,
130 const struct MConfig* cfg,
131 const struct Capabilities* caps,
132 const struct HWState* hs,
136 int n = firstbit(~ms->touch_used);
137 const struct FingerState* fs = &hs->data[fn];
139 xf86Msg(X_WARNING, "Too many touches to track. Ignoring touch %d.\n", fs->tracking_id);
141 x = cfg->axis_x_invert ? get_cap_xflip(caps, fs->position_x) : fs->position_x;
142 y = cfg->axis_y_invert ? get_cap_yflip(caps, fs->position_y) : fs->position_y;
143 ms->touch[n].state = 0U;
144 ms->touch[n].flags = 0U;
145 timercp(&ms->touch[n].down, &hs->evtime);
146 ms->touch[n].direction = TR_NONE;
147 ms->touch[n].tracking_id = fs->tracking_id;
152 ms->touch[n].total_dx = 0;
153 ms->touch[n].total_dy = 0;
154 SETBIT(ms->touch[n].state, MT_NEW);
155 SETBIT(ms->touch_used, n);
162 static void touch_update(struct MTState* ms,
163 const struct MConfig* cfg,
164 const struct Capabilities* caps,
165 const struct FingerState* fs,
169 x = cfg->axis_x_invert ? get_cap_xflip(caps, fs->position_x) : fs->position_x;
170 y = cfg->axis_y_invert ? get_cap_yflip(caps, fs->position_y) : fs->position_y;
171 ms->touch[touch].dx = x - ms->touch[touch].x;
172 ms->touch[touch].dy = y - ms->touch[touch].y;
173 ms->touch[touch].total_dx += ms->touch[touch].dx;
174 ms->touch[touch].total_dy += ms->touch[touch].dy;
175 ms->touch[touch].x = x;
176 ms->touch[touch].y = y;
177 ms->touch[touch].direction = trig_direction(ms->touch[touch].dx, ms->touch[touch].dy);
178 CLEARBIT(ms->touch[touch].state, MT_NEW);
183 static void touch_release(struct MTState* ms,
186 ms->touch[touch].dx = 0;
187 ms->touch[touch].dy = 0;
188 ms->touch[touch].direction = TR_NONE;
189 CLEARBIT(ms->touch[touch].state, MT_NEW);
190 SETBIT(ms->touch[touch].state, MT_RELEASED);
193 /* Invalidate all touches.
195 static void touches_invalidate(struct MTState* ms)
198 foreach_bit(i, ms->touch_used)
199 SETBIT(ms->touch[i].state, MT_INVALID);
202 /* Update all touches.
204 static void touches_update(struct MTState* ms,
205 const struct MConfig* cfg,
206 const struct HWState* hs,
207 const struct Capabilities* caps)
209 int i, n, disable = 0;
210 // Release missing touches.
211 foreach_bit(i, ms->touch_used) {
212 if (find_finger(hs, ms->touch[i].tracking_id) == -1)
213 touch_release(ms, i);
216 // Add and update touches.
217 foreach_bit(i, hs->used) {
218 n = find_touch(ms, hs->data[i].tracking_id);
220 if (is_release(cfg, &hs->data[i]))
221 touch_release(ms, n);
223 touch_update(ms, cfg, caps, &hs->data[i], n);
225 else if (is_touch(cfg, &hs->data[i]))
226 n = touch_append(ms, cfg, caps, hs, i);
229 // Track and invalidate thumb, palm, and bottom edge touches.
230 if (is_thumb(cfg, &hs->data[i]))
231 SETBIT(ms->touch[n].state, MT_THUMB);
233 CLEARBIT(ms->touch[n].state, MT_THUMB);
235 if (is_palm(cfg, &hs->data[i]))
236 SETBIT(ms->touch[n].state, MT_PALM);
238 CLEARBIT(ms->touch[n].state, MT_PALM);
240 if ((ms->touch[n].y - get_cap_ymin(caps)) > (100 - cfg->bottom_edge)*cfg->pad_height/100) {
241 if (GETBIT(ms->touch[n].state, MT_NEW))
242 SETBIT(ms->touch[n].state, MT_BOTTOM_EDGE);
245 CLEARBIT(ms->touch[n].state, MT_BOTTOM_EDGE);
247 MODBIT(ms->touch[n].state, MT_INVALID,
248 GETBIT(ms->touch[n].state, MT_THUMB) && cfg->ignore_thumb ||
249 GETBIT(ms->touch[n].state, MT_PALM) && cfg->ignore_palm ||
250 GETBIT(ms->touch[n].state, MT_BOTTOM_EDGE));
252 disable |= cfg->disable_on_thumb && GETBIT(ms->touch[n].state, MT_THUMB);
253 disable |= cfg->disable_on_palm && GETBIT(ms->touch[n].state, MT_PALM);
258 touches_invalidate(ms);
261 /* Remove released touches.
263 static void touches_clean(struct MTState* ms)
266 used = ms->touch_used;
267 foreach_bit(i, used) {
268 if (GETBIT(ms->touch[i].state, MT_RELEASED))
269 CLEARBIT(ms->touch_used, i);
274 static void mtstate_output(const struct MTState* ms,
275 const struct HWState* hs)
280 n = bitcount(ms->touch_used);
281 if (bitcount(ms->touch_used) > 0) {
283 xf86Msg(X_INFO, "mtstate: %d touches at event time %llu (rt %llu)\n",
284 n, timertoms(&hs->evtime), timertoms(&tv));
286 foreach_bit(i, ms->touch_used) {
287 if (GETBIT(ms->touch[i].state, MT_RELEASED)) {
288 timersub(&hs->evtime, &ms->touch[i].down, &tv);
289 xf86Msg(X_INFO, " released p(%d, %d) d(%d, %d) dir(%f) down(%llu) state("PRBITMASK") time(%lld)\n",
290 ms->touch[i].x, ms->touch[i].y, ms->touch[i].dx, ms->touch[i].dy,
291 ms->touch[i].direction, timertoms(&ms->touch[i].down), ms->touch[i].state, timertoms(&tv));
293 else if (GETBIT(ms->touch[i].state, MT_NEW)) {
294 xf86Msg(X_INFO, " new p(%d, %d) d(%d, %d) dir(%f) down(%llu) state("PRBITMASK")\n",
295 ms->touch[i].x, ms->touch[i].y, ms->touch[i].dx, ms->touch[i].dy,
296 ms->touch[i].direction, timertoms(&ms->touch[i].down), ms->touch[i].state);
298 else if (GETBIT(ms->touch[i].state, MT_INVALID)) {
299 timersub(&hs->evtime, &ms->touch[i].down, &tv);
300 xf86Msg(X_INFO, " invalid p(%d, %d) d(%d, %d) dir(%f) down(%llu) state("PRBITMASK") time(%lld)\n",
301 ms->touch[i].x, ms->touch[i].y, ms->touch[i].dx, ms->touch[i].dy,
302 ms->touch[i].direction, timertoms(&ms->touch[i].down), ms->touch[i].state, timertoms(&tv));
305 xf86Msg(X_INFO, " touching p(%d, %d) d(%d, %d) dir(%f) down(%llu) state("PRBITMASK")\n",
306 ms->touch[i].x, ms->touch[i].y, ms->touch[i].dx, ms->touch[i].dy,
307 ms->touch[i].direction, timertoms(&ms->touch[i].down), ms->touch[i].state);
313 void mtstate_init(struct MTState* ms)
315 memset(ms, 0, sizeof(struct MTState));
318 // Process changes in touch state.
319 void mtstate_extract(struct MTState* ms,
320 const struct MConfig* cfg,
321 const struct HWState* hs,
322 const struct Capabilities* caps)
327 touches_update(ms, cfg, hs, caps);
330 mtstate_output(ms, hs);