chiark / gitweb /
Offsets: In button zone code, cope with negative "pos" values
[xf86-input-mtrack.git] / driver / mtrack.c
1 /***************************************************************************
2  *
3  * Multitouch X driver
4  * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
5  * Copyright (C) 2011 Ryan Bourgeois <bluedragonx@gmail.com>
6  *
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.
11  *
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.
16  *
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
20  *
21  **************************************************************************/
22
23 #include "mtouch.h"
24 #include "mprops.h"
25
26 #include <xf86Module.h>
27 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
28 #include <X11/Xatom.h>
29 #include <xserver-properties.h>
30 #endif
31
32 #define TAP_HOLD 100
33 #define TAP_TIMEOUT 200
34 #define TAP_THRESHOLD 0.05
35 #define TICK_TIMEOUT 50
36 #define SCROLL_THRESHOLD 0.05
37 #define SWIPE_THRESHOLD 0.15
38 #define SCALE_THRESHOLD 0.15
39 #define ROTATE_THRESHOLD 0.15
40
41 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
42 typedef InputInfoPtr LocalDevicePtr;
43 #endif
44
45 /* button mapping simplified */
46 #define PROPMAP(m, x, y) m[x] = XIGetKnownProperty(y)
47
48 static void pointer_control(DeviceIntPtr dev, PtrCtrl *ctrl)
49 {
50 #if DEBUG_DRIVER
51         xf86Msg(X_INFO, "pointer_control\n");
52 #endif
53 }
54
55 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
56 static void initAxesLabels(Atom map[2])
57 {
58         memset(map, 0, 2 * sizeof(Atom));
59         PROPMAP(map, 0, AXIS_LABEL_PROP_REL_X);
60         PROPMAP(map, 1, AXIS_LABEL_PROP_REL_Y);
61 }
62
63 static void initButtonLabels(Atom map[DIM_BUTTON])
64 {
65         memset(map, 0, DIM_BUTTON * sizeof(Atom));
66         PROPMAP(map, MT_BUTTON_LEFT, BTN_LABEL_PROP_BTN_LEFT);
67         PROPMAP(map, MT_BUTTON_MIDDLE, BTN_LABEL_PROP_BTN_MIDDLE);
68         PROPMAP(map, MT_BUTTON_RIGHT, BTN_LABEL_PROP_BTN_RIGHT);
69         PROPMAP(map, MT_BUTTON_WHEEL_UP, BTN_LABEL_PROP_BTN_WHEEL_UP);
70         PROPMAP(map, MT_BUTTON_WHEEL_DOWN, BTN_LABEL_PROP_BTN_WHEEL_DOWN);
71         PROPMAP(map, MT_BUTTON_HWHEEL_LEFT, BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
72         PROPMAP(map, MT_BUTTON_HWHEEL_RIGHT, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
73         /* how to map swipe buttons? */
74         PROPMAP(map, MT_BUTTON_SWIPE_UP, BTN_LABEL_PROP_BTN_0);
75         PROPMAP(map, MT_BUTTON_SWIPE_DOWN, BTN_LABEL_PROP_BTN_1);
76         PROPMAP(map, MT_BUTTON_SWIPE_LEFT, BTN_LABEL_PROP_BTN_2);
77         PROPMAP(map, MT_BUTTON_SWIPE_RIGHT, BTN_LABEL_PROP_BTN_3);
78         /* how to map scale and rotate? */
79         PROPMAP(map, MT_BUTTON_SCALE_DOWN, BTN_LABEL_PROP_BTN_4);
80         PROPMAP(map, MT_BUTTON_SCALE_UP, BTN_LABEL_PROP_BTN_5);
81         PROPMAP(map, MT_BUTTON_ROTATE_LEFT, BTN_LABEL_PROP_BTN_6);
82         PROPMAP(map, MT_BUTTON_ROTATE_RIGHT, BTN_LABEL_PROP_BTN_7);
83 }
84 #endif
85
86 static int device_init(DeviceIntPtr dev, LocalDevicePtr local)
87 {
88         struct MTouch *mt = local->private;
89         unsigned char btmap[DIM_BUTTON + 1] = {
90                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
91         };
92 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
93         Atom axes_labels[2], btn_labels[DIM_BUTTON];
94         initAxesLabels(axes_labels);
95         initButtonLabels(btn_labels);
96 #endif
97
98         local->fd = xf86OpenSerial(local->options);
99         if (local->fd < 0) {
100                 xf86Msg(X_ERROR, "mtrack: cannot open device\n");
101                 return !Success;
102         }
103         if (mtouch_configure(mt, local->fd)) {
104                 xf86Msg(X_ERROR, "mtrack: cannot configure device\n");
105                 return !Success;
106         }
107         xf86CloseSerial(local->fd);
108
109 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
110         InitPointerDeviceStruct((DevicePtr)dev,
111                                 btmap, DIM_BUTTON,
112                                 GetMotionHistory,
113                                 pointer_control,
114                                 GetMotionHistorySize(),
115                                 2);
116 #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
117         InitPointerDeviceStruct((DevicePtr)dev,
118                                 btmap, DIM_BUTTON,
119                                 pointer_control,
120                                 GetMotionHistorySize(),
121                                 2);
122 #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
123         InitPointerDeviceStruct((DevicePtr)dev,
124                                 btmap, DIM_BUTTON, btn_labels,
125                                 pointer_control,
126                                 GetMotionHistorySize(),
127                                 2, axes_labels);
128 #else
129 #error "Unsupported ABI_XINPUT_VERSION"
130 #endif
131
132         xf86InitValuatorAxisStruct(dev, 0,
133 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
134                                    axes_labels[0],
135 #endif
136                                    mt->caps.abs[MTDEV_POSITION_X].minimum,
137                                    mt->caps.abs[MTDEV_POSITION_X].maximum,
138 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
139                                    1, 0, 1, Absolute);
140 #else
141                                    1, 0, 1);
142 #endif
143         xf86InitValuatorDefaults(dev, 0);
144         xf86InitValuatorAxisStruct(dev, 1,
145 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
146                                    axes_labels[1],
147 #endif
148                                    mt->caps.abs[MTDEV_POSITION_Y].minimum,
149                                    mt->caps.abs[MTDEV_POSITION_Y].maximum,
150 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
151                                    1, 0, 1, Absolute);
152 #else
153                                    1, 0, 1);
154 #endif
155         xf86InitValuatorDefaults(dev, 1);
156         mprops_init(&mt->cfg, local);
157         XIRegisterPropertyHandler(dev, mprops_set_property, NULL, NULL);
158
159         return Success;
160 }
161
162 static int device_on(LocalDevicePtr local)
163 {
164         struct MTouch *mt = local->private;
165         local->fd = xf86OpenSerial(local->options);
166         if (local->fd < 0) {
167                 xf86Msg(X_ERROR, "mtrack: cannot open device\n");
168                 return !Success;
169         }
170         if (mtouch_open(mt, local->fd)) {
171                 xf86Msg(X_ERROR, "mtrack: cannot grab device\n");
172                 return !Success;
173         }
174         xf86AddEnabledDevice(local);
175         return Success;
176 }
177
178 static int device_off(LocalDevicePtr local)
179 {
180         struct MTouch *mt = local->private;
181         xf86RemoveEnabledDevice(local);
182         if (mtouch_close(mt))
183                 xf86Msg(X_WARNING, "mtrack: cannot ungrab device\n");
184         xf86CloseSerial(local->fd);
185         return Success;
186 }
187
188 static int device_close(LocalDevicePtr local)
189 {
190         return Success;
191 }
192
193 static void handle_gestures(LocalDevicePtr local,
194                         const struct Gestures* gs)
195 {
196         static bitmask_t buttons_prev = 0U;
197         int i;
198
199         for (i = 0; i < 32; i++) {
200                 if (GETBIT(gs->buttons, i) == GETBIT(buttons_prev, i))
201                         continue;
202                 if (GETBIT(gs->buttons, i)) {
203                         xf86PostButtonEvent(local->dev, FALSE, i+1, 1, 0, 0);
204 #if DEBUG_DRIVER
205                         xf86Msg(X_INFO, "button %d down\n", i+1);
206 #endif
207                 }
208                 else {
209                         xf86PostButtonEvent(local->dev, FALSE, i+1, 0, 0, 0);
210 #if DEBUG_DRIVER
211                         xf86Msg(X_INFO, "button %d up\n", i+1);
212 #endif
213                 }
214         }
215         buttons_prev = gs->buttons;
216
217         if (gs->move_dx != 0 || gs->move_dy != 0)
218                 xf86PostMotionEvent(local->dev, 0, 0, 2, gs->move_dx, gs->move_dy);
219 }
220
221 /* called for each full received packet from the touchpad */
222 static void read_input(LocalDevicePtr local)
223 {
224         struct MTouch *mt = local->private;
225         while (mtouch_read(mt) > 0)
226                 handle_gestures(local, &mt->gs);
227         if (mtouch_delayed(mt))
228                 handle_gestures(local, &mt->gs);
229 }
230
231 static Bool device_control(DeviceIntPtr dev, int mode)
232 {
233         LocalDevicePtr local = dev->public.devicePrivate;
234         switch (mode) {
235         case DEVICE_INIT:
236                 xf86Msg(X_INFO, "device control: init\n");
237                 return device_init(dev, local);
238         case DEVICE_ON:
239                 xf86Msg(X_INFO, "device control: on\n");
240                 return device_on(local);
241         case DEVICE_OFF:
242                 xf86Msg(X_INFO, "device control: off\n");
243                 return device_off(local);
244         case DEVICE_CLOSE:
245                 xf86Msg(X_INFO, "device control: close\n");
246                 return device_close(local);
247         default:
248                 xf86Msg(X_INFO, "device control: default\n");
249                 return BadValue;
250         }
251 }
252
253
254 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
255 static int preinit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
256 {
257         struct MTouch *mt;
258
259         mt = calloc(1, sizeof(*mt));
260         if (!mt)
261                 return BadAlloc;
262
263         pInfo->private = mt;
264         pInfo->type_name = XI_TOUCHPAD;
265         pInfo->device_control = device_control;
266         pInfo->read_input = read_input;
267         pInfo->switch_mode = 0;
268
269     xf86CollectInputOptions(pInfo, NULL);
270     xf86OptionListReport(pInfo->options);
271     xf86ProcessCommonOptions(pInfo, pInfo->options);
272     mconfig_configure(&mt->cfg, pInfo->options);
273
274         return Success;
275 }
276 #else
277 static InputInfoPtr preinit(InputDriverPtr drv, IDevPtr dev, int flags)
278 {
279         struct MTouch *mt;
280         InputInfoPtr local = xf86AllocateInput(drv, 0);
281         if (!local)
282                 goto error;
283         mt = calloc(1, sizeof(struct MTouch));
284         if (!mt)
285                 goto error;
286
287         local->name = dev->identifier;
288         local->type_name = XI_TOUCHPAD;
289         local->device_control = device_control;
290         local->read_input = read_input;
291         local->private = mt;
292         local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
293         local->conf_idev = dev;
294
295         xf86CollectInputOptions(local, NULL, NULL);
296         xf86OptionListReport(local->options);
297         xf86ProcessCommonOptions(local, local->options);
298         mconfig_configure(&mt->cfg, local->options);
299
300         local->flags |= XI86_CONFIGURED;
301  error:
302         return local;
303 }
304 #endif
305
306 static void uninit(InputDriverPtr drv, InputInfoPtr local, int flags)
307 {
308         free(local->private);
309         local->private = 0;
310         xf86DeleteInput(local, 0);
311 }
312
313 static InputDriverRec MTRACK = {
314         1,
315         "mtrack",
316         NULL,
317         preinit,
318         uninit,
319         NULL,
320         0
321 };
322
323 static XF86ModuleVersionInfo moduleVersion = {
324         "mtrack",
325         MODULEVENDORSTRING,
326         MODINFOSTRING1,
327         MODINFOSTRING2,
328         XORG_VERSION_CURRENT,
329         0, 1, 0,
330         ABI_CLASS_XINPUT,
331         ABI_XINPUT_VERSION,
332         MOD_CLASS_XINPUT,
333         {0, 0, 0, 0}
334 };
335
336 static pointer setup(pointer module, pointer options, int *errmaj, int *errmin)
337 {
338         xf86AddInputDriver(&MTRACK, module, 0);
339         return module;
340 }
341
342 _X_EXPORT XF86ModuleData mtrackModuleData = {&moduleVersion, &setup, NULL };