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 #include <xf86Module.h>
27 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
28 #include <X11/Xatom.h>
29 #include <xserver-properties.h>
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
41 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
42 typedef InputInfoPtr LocalDevicePtr;
45 /* button mapping simplified */
46 #define PROPMAP(m, x, y) m[x] = XIGetKnownProperty(y)
48 static void pointer_control(DeviceIntPtr dev, PtrCtrl *ctrl)
51 xf86Msg(X_INFO, "pointer_control\n");
55 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
56 static void initAxesLabels(Atom map[2])
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);
63 static void initButtonLabels(Atom map[DIM_BUTTON])
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);
86 static int device_init(DeviceIntPtr dev, LocalDevicePtr local)
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
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);
98 local->fd = xf86OpenSerial(local->options);
100 xf86Msg(X_ERROR, "mtrack: cannot open device\n");
103 if (mtouch_configure(mt, local->fd)) {
104 xf86Msg(X_ERROR, "mtrack: cannot configure device\n");
107 xf86CloseSerial(local->fd);
109 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
110 InitPointerDeviceStruct((DevicePtr)dev,
114 GetMotionHistorySize(),
116 #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7
117 InitPointerDeviceStruct((DevicePtr)dev,
120 GetMotionHistorySize(),
122 #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
123 InitPointerDeviceStruct((DevicePtr)dev,
124 btmap, DIM_BUTTON, btn_labels,
126 GetMotionHistorySize(),
129 #error "Unsupported ABI_XINPUT_VERSION"
132 xf86InitValuatorAxisStruct(dev, 0,
133 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
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
143 xf86InitValuatorDefaults(dev, 0);
144 xf86InitValuatorAxisStruct(dev, 1,
145 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
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
155 xf86InitValuatorDefaults(dev, 1);
156 mprops_init(&mt->cfg, local);
157 XIRegisterPropertyHandler(dev, mprops_set_property, NULL, NULL);
162 static int device_on(LocalDevicePtr local)
164 struct MTouch *mt = local->private;
165 local->fd = xf86OpenSerial(local->options);
167 xf86Msg(X_ERROR, "mtrack: cannot open device\n");
170 if (mtouch_open(mt, local->fd)) {
171 xf86Msg(X_ERROR, "mtrack: cannot grab device\n");
174 xf86AddEnabledDevice(local);
178 static int device_off(LocalDevicePtr local)
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);
188 static int device_close(LocalDevicePtr local)
193 static void handle_gestures(LocalDevicePtr local,
194 const struct Gestures* gs)
196 static bitmask_t buttons_prev = 0U;
199 for (i = 0; i < 32; i++) {
200 if (GETBIT(gs->buttons, i) == GETBIT(buttons_prev, i))
202 if (GETBIT(gs->buttons, i)) {
203 xf86PostButtonEvent(local->dev, FALSE, i+1, 1, 0, 0);
205 xf86Msg(X_INFO, "button %d down\n", i+1);
209 xf86PostButtonEvent(local->dev, FALSE, i+1, 0, 0, 0);
211 xf86Msg(X_INFO, "button %d up\n", i+1);
215 buttons_prev = gs->buttons;
217 if (gs->move_dx != 0 || gs->move_dy != 0)
218 xf86PostMotionEvent(local->dev, 0, 0, 2, gs->move_dx, gs->move_dy);
221 /* called for each full received packet from the touchpad */
222 static void read_input(LocalDevicePtr local)
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);
231 static Bool device_control(DeviceIntPtr dev, int mode)
233 LocalDevicePtr local = dev->public.devicePrivate;
236 xf86Msg(X_INFO, "device control: init\n");
237 return device_init(dev, local);
239 xf86Msg(X_INFO, "device control: on\n");
240 return device_on(local);
242 xf86Msg(X_INFO, "device control: off\n");
243 return device_off(local);
245 xf86Msg(X_INFO, "device control: close\n");
246 return device_close(local);
248 xf86Msg(X_INFO, "device control: default\n");
254 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
255 static int preinit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
259 mt = calloc(1, sizeof(*mt));
264 pInfo->type_name = XI_TOUCHPAD;
265 pInfo->device_control = device_control;
266 pInfo->read_input = read_input;
267 pInfo->switch_mode = 0;
269 xf86CollectInputOptions(pInfo, NULL);
270 xf86OptionListReport(pInfo->options);
271 xf86ProcessCommonOptions(pInfo, pInfo->options);
272 mconfig_configure(&mt->cfg, pInfo->options);
277 static InputInfoPtr preinit(InputDriverPtr drv, IDevPtr dev, int flags)
280 InputInfoPtr local = xf86AllocateInput(drv, 0);
283 mt = calloc(1, sizeof(struct MTouch));
287 local->name = dev->identifier;
288 local->type_name = XI_TOUCHPAD;
289 local->device_control = device_control;
290 local->read_input = read_input;
292 local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
293 local->conf_idev = dev;
295 xf86CollectInputOptions(local, NULL, NULL);
296 xf86OptionListReport(local->options);
297 xf86ProcessCommonOptions(local, local->options);
298 mconfig_configure(&mt->cfg, local->options);
300 local->flags |= XI86_CONFIGURED;
306 static void uninit(InputDriverPtr drv, InputInfoPtr local, int flags)
308 free(local->private);
310 xf86DeleteInput(local, 0);
313 static InputDriverRec MTRACK = {
323 static XF86ModuleVersionInfo moduleVersion = {
328 XORG_VERSION_CURRENT,
336 static pointer setup(pointer module, pointer options, int *errmaj, int *errmin)
338 xf86AddInputDriver(&MTRACK, module, 0);
342 _X_EXPORT XF86ModuleData mtrackModuleData = {&moduleVersion, &setup, NULL };