2 * Copyright © 2014 Red Hat, Inc.
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 #define TOUCHPAD_HISTORY_LENGTH 4
32 #define tp_for_each_touch(_tp, _t) \
33 for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++)
48 enum touch_state state;
55 struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH];
62 struct evdev_dispatch base;
63 struct evdev_device *device;
64 unsigned int nfingers_down; /* number of fingers down */
65 unsigned int slot; /* current slot */
67 unsigned int ntouches; /* number of slots */
68 struct tp_touch *touches; /* len == ntouches */
71 static inline struct tp_motion *
72 tp_motion_history_offset(struct tp_touch *t, int offset)
75 (t->history.index - offset + TOUCHPAD_HISTORY_LENGTH) %
76 TOUCHPAD_HISTORY_LENGTH;
78 return &t->history.samples[offset_index];
82 tp_motion_history_push(struct tp_touch *t)
84 int motion_index = (t->history.index + 1) % TOUCHPAD_HISTORY_LENGTH;
86 if (t->history.count < TOUCHPAD_HISTORY_LENGTH)
89 t->history.samples[motion_index].x = t->x;
90 t->history.samples[motion_index].y = t->y;
91 t->history.index = motion_index;
95 tp_motion_history_reset(struct tp_touch *t)
100 static inline struct tp_touch *
101 tp_current_touch(struct tp_dispatch *tp)
103 return &tp->touches[min(tp->slot, tp->ntouches)];
107 tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t)
109 if (t->state != TOUCH_UPDATE) {
110 tp_motion_history_reset(t);
112 t->state = TOUCH_BEGIN;
114 assert(tp->nfingers_down >= 1);
119 tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t)
121 if (t->state == TOUCH_NONE)
125 t->state = TOUCH_END;
126 assert(tp->nfingers_down >= 1);
131 tp_estimate_delta(int x0, int x1, int x2, int x3)
133 return (x0 + x1 - x2 - x3) / 4;
137 tp_get_delta(struct tp_touch *t, double *dx, double *dy)
139 if (t->history.count < 4) {
145 *dx = tp_estimate_delta(tp_motion_history_offset(t, 0)->x,
146 tp_motion_history_offset(t, 1)->x,
147 tp_motion_history_offset(t, 2)->x,
148 tp_motion_history_offset(t, 3)->x);
149 *dy = tp_estimate_delta(tp_motion_history_offset(t, 0)->y,
150 tp_motion_history_offset(t, 1)->y,
151 tp_motion_history_offset(t, 2)->y,
152 tp_motion_history_offset(t, 3)->y);
156 tp_process_absolute(struct tp_dispatch *tp,
157 const struct input_event *e,
160 struct tp_touch *t = tp_current_touch(tp);
163 case ABS_MT_POSITION_X:
168 case ABS_MT_POSITION_Y:
176 case ABS_MT_TRACKING_ID:
179 tp_begin_touch(tp, t);
186 tp_process_key(struct tp_dispatch *tp,
187 const struct input_event *e,
194 pointer_notify_button(
198 e->value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED :
199 LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
205 tp_process_state(struct tp_dispatch *tp, uint32_t time)
209 tp_for_each_touch(tp, t) {
213 tp_motion_history_push(t);
218 tp_post_process_state(struct tp_dispatch *tp, uint32_t time)
222 tp_for_each_touch(tp, t) {
226 if (t->state == TOUCH_END)
227 t->state = TOUCH_NONE;
228 else if (t->state == TOUCH_BEGIN)
229 t->state = TOUCH_UPDATE;
236 tp_post_events(struct tp_dispatch *tp, uint32_t time)
238 struct tp_touch *t = tp_current_touch(tp);
241 if (tp->nfingers_down != 1)
244 tp_get_delta(t, &dx, &dy);
246 if (dx != 0 || dy != 0)
247 pointer_notify_motion(
250 li_fixed_from_double(dx),
251 li_fixed_from_double(dy));
255 tp_process(struct evdev_dispatch *dispatch,
256 struct evdev_device *device,
257 struct input_event *e,
260 struct tp_dispatch *tp =
261 (struct tp_dispatch *)dispatch;
265 tp_process_absolute(tp, e, time);
268 tp_process_key(tp, e, time);
271 tp_process_state(tp, time);
272 tp_post_events(tp, time);
273 tp_post_process_state(tp, time);
279 tp_destroy(struct evdev_dispatch *dispatch)
281 struct tp_dispatch *tp =
282 (struct tp_dispatch*)dispatch;
288 static struct evdev_dispatch_interface tp_interface = {
294 tp_init_slots(struct tp_dispatch *tp,
295 struct evdev_device *device)
297 struct input_absinfo absinfo = {0};
299 ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT), &absinfo);
301 tp->ntouches = absinfo.maximum + 1;
302 tp->touches = calloc(tp->ntouches,
303 sizeof(struct tp_touch));
304 tp->slot = absinfo.value;
311 tp_init(struct tp_dispatch *tp,
312 struct evdev_device *device)
314 tp->base.interface = &tp_interface;
317 if (tp_init_slots(tp, device) != 0)
323 struct evdev_dispatch *
324 evdev_mt_touchpad_create(struct evdev_device *device)
326 struct tp_dispatch *tp;
328 tp = zalloc(sizeof *tp);
332 if (tp_init(tp, device) != 0) {
333 tp_destroy(&tp->base);