diff options
Diffstat (limited to 'driver')
| -rw-r--r-- | driver/multitouch.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/driver/multitouch.c b/driver/multitouch.c new file mode 100644 index 0000000..7e275b3 --- /dev/null +++ b/driver/multitouch.c | |||
| @@ -0,0 +1,369 @@ | |||
| 1 | /*************************************************************************** | ||
| 2 | * | ||
| 3 | * Multitouch X driver | ||
| 4 | * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | * | ||
| 20 | **************************************************************************/ | ||
| 21 | |||
| 22 | #include "gestures.h" | ||
| 23 | |||
| 24 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 25 | #include <X11/Xatom.h> | ||
| 26 | #include <xserver-properties.h> | ||
| 27 | #endif | ||
| 28 | |||
| 29 | /* these should be user-configurable at some point */ | ||
| 30 | static const float vscroll_fraction = 0.05; | ||
| 31 | static const float hscroll_fraction = 0.05; | ||
| 32 | static const float vswipe_fraction = 0.25; | ||
| 33 | static const float hswipe_fraction = 0.25; | ||
| 34 | static const float scale_fraction = 0.05; | ||
| 35 | static const float rot_fraction = 0.05; | ||
| 36 | |||
| 37 | /* flip these to enable event debugging */ | ||
| 38 | #if 1 | ||
| 39 | #define TRACE1(format, arg1) | ||
| 40 | #define TRACE2(format, arg1, arg2) | ||
| 41 | #else | ||
| 42 | #define TRACE1(format, arg1) xf86Msg(X_INFO, format, arg1) | ||
| 43 | #define TRACE2(format, arg1, arg2) xf86Msg(X_INFO, format, arg1, arg2) | ||
| 44 | #endif | ||
| 45 | |||
| 46 | /* button mapping simplified */ | ||
| 47 | #define PROPMAP(m, x, y) m[x] = XIGetKnownProperty(y) | ||
| 48 | |||
| 49 | static void pointer_control(DeviceIntPtr dev, PtrCtrl *ctrl) | ||
| 50 | { | ||
| 51 | xf86Msg(X_INFO, "pointer_control\n"); | ||
| 52 | } | ||
| 53 | |||
| 54 | static int pointer_property(DeviceIntPtr dev, | ||
| 55 | Atom property, | ||
| 56 | XIPropertyValuePtr prop, | ||
| 57 | BOOL checkonly) | ||
| 58 | { | ||
| 59 | xf86Msg(X_INFO, "pointer_property\n"); | ||
| 60 | return Success; | ||
| 61 | } | ||
| 62 | |||
| 63 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 64 | static void initAxesLabels(Atom map[2]) | ||
| 65 | { | ||
| 66 | memset(map, 0, 2 * sizeof(Atom)); | ||
| 67 | PROPMAP(map, 0, AXIS_LABEL_PROP_REL_X); | ||
| 68 | PROPMAP(map, 1, AXIS_LABEL_PROP_REL_Y); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void initButtonLabels(Atom map[DIM_BUTTON]) | ||
| 72 | { | ||
| 73 | memset(map, 0, DIM_BUTTON * sizeof(Atom)); | ||
| 74 | PROPMAP(map, MT_BUTTON_LEFT, BTN_LABEL_PROP_BTN_LEFT); | ||
| 75 | PROPMAP(map, MT_BUTTON_MIDDLE, BTN_LABEL_PROP_BTN_MIDDLE); | ||
| 76 | PROPMAP(map, MT_BUTTON_RIGHT, BTN_LABEL_PROP_BTN_RIGHT); | ||
| 77 | PROPMAP(map, MT_BUTTON_WHEEL_UP, BTN_LABEL_PROP_BTN_WHEEL_UP); | ||
| 78 | PROPMAP(map, MT_BUTTON_WHEEL_DOWN, BTN_LABEL_PROP_BTN_WHEEL_DOWN); | ||
| 79 | PROPMAP(map, MT_BUTTON_HWHEEL_LEFT, BTN_LABEL_PROP_BTN_HWHEEL_LEFT); | ||
| 80 | PROPMAP(map, MT_BUTTON_HWHEEL_RIGHT, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); | ||
| 81 | /* how to map swipe buttons? */ | ||
| 82 | PROPMAP(map, MT_BUTTON_SWIPE_UP, BTN_LABEL_PROP_BTN_0); | ||
| 83 | PROPMAP(map, MT_BUTTON_SWIPE_DOWN, BTN_LABEL_PROP_BTN_1); | ||
| 84 | PROPMAP(map, MT_BUTTON_SWIPE_LEFT, BTN_LABEL_PROP_BTN_2); | ||
| 85 | PROPMAP(map, MT_BUTTON_SWIPE_RIGHT, BTN_LABEL_PROP_BTN_3); | ||
| 86 | /* how to map scale and rotate? */ | ||
| 87 | PROPMAP(map, MT_BUTTON_SCALE_DOWN, BTN_LABEL_PROP_BTN_4); | ||
| 88 | PROPMAP(map, MT_BUTTON_SCALE_UP, BTN_LABEL_PROP_BTN_5); | ||
| 89 | PROPMAP(map, MT_BUTTON_ROTATE_LEFT, BTN_LABEL_PROP_BTN_6); | ||
| 90 | PROPMAP(map, MT_BUTTON_ROTATE_RIGHT, BTN_LABEL_PROP_BTN_7); | ||
| 91 | } | ||
| 92 | #endif | ||
| 93 | |||
| 94 | static int device_init(DeviceIntPtr dev, LocalDevicePtr local) | ||
| 95 | { | ||
| 96 | struct MTouch *mt = local->private; | ||
| 97 | unsigned char btmap[DIM_BUTTON + 1] = { | ||
| 98 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 99 | }; | ||
| 100 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 101 | Atom axes_labels[2], btn_labels[DIM_BUTTON]; | ||
| 102 | initAxesLabels(axes_labels); | ||
| 103 | initButtonLabels(btn_labels); | ||
| 104 | #endif | ||
| 105 | |||
| 106 | local->fd = xf86OpenSerial(local->options); | ||
| 107 | if (local->fd < 0) { | ||
| 108 | xf86Msg(X_ERROR, "multitouch: cannot open device\n"); | ||
| 109 | return !Success; | ||
| 110 | } | ||
| 111 | if (configure_mtouch(mt, local->fd)) { | ||
| 112 | xf86Msg(X_ERROR, "multitouch: cannot configure device\n"); | ||
| 113 | return !Success; | ||
| 114 | } | ||
| 115 | xf86CloseSerial(local->fd); | ||
| 116 | |||
| 117 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3 | ||
| 118 | InitPointerDeviceStruct((DevicePtr)dev, | ||
| 119 | btmap, DIM_BUTTON, | ||
| 120 | GetMotionHistory, | ||
| 121 | pointer_control, | ||
| 122 | GetMotionHistorySize(), | ||
| 123 | 2); | ||
| 124 | #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7 | ||
| 125 | InitPointerDeviceStruct((DevicePtr)dev, | ||
| 126 | btmap, DIM_BUTTON, | ||
| 127 | pointer_control, | ||
| 128 | GetMotionHistorySize(), | ||
| 129 | 2); | ||
| 130 | #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 131 | InitPointerDeviceStruct((DevicePtr)dev, | ||
| 132 | btmap, DIM_BUTTON, btn_labels, | ||
| 133 | pointer_control, | ||
| 134 | GetMotionHistorySize(), | ||
| 135 | 2, axes_labels); | ||
| 136 | #else | ||
| 137 | #error "Unsupported ABI_XINPUT_VERSION" | ||
| 138 | #endif | ||
| 139 | |||
| 140 | xf86InitValuatorAxisStruct(dev, 0, | ||
| 141 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 142 | axes_labels[0], | ||
| 143 | #endif | ||
| 144 | mt->caps.abs_position_x.minimum, | ||
| 145 | mt->caps.abs_position_x.maximum, | ||
| 146 | 1, 0, 1); | ||
| 147 | xf86InitValuatorDefaults(dev, 0); | ||
| 148 | xf86InitValuatorAxisStruct(dev, 1, | ||
| 149 | #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 | ||
| 150 | axes_labels[1], | ||
| 151 | #endif | ||
| 152 | mt->caps.abs_position_y.minimum, | ||
| 153 | mt->caps.abs_position_y.maximum, | ||
| 154 | 1, 0, 1); | ||
| 155 | xf86InitValuatorDefaults(dev, 1); | ||
| 156 | |||
| 157 | XIRegisterPropertyHandler(dev, pointer_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, "multitouch: cannot open device\n"); | ||
| 168 | return !Success; | ||
| 169 | } | ||
| 170 | if (open_mtouch(mt, local->fd)) { | ||
| 171 | xf86Msg(X_ERROR, "multitouch: 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 (close_mtouch(mt, local->fd)) | ||
| 183 | xf86Msg(X_WARNING, "multitouch: 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 tickle_button(LocalDevicePtr local, int id) | ||
| 194 | { | ||
| 195 | xf86PostButtonEvent(local->dev, FALSE, id, 1, 0, 0); | ||
| 196 | xf86PostButtonEvent(local->dev, FALSE, id, 0, 0, 0); | ||
| 197 | } | ||
| 198 | |||
| 199 | static void button_scroll(LocalDevicePtr local, | ||
| 200 | int btdec, int btinc, | ||
| 201 | int *scroll, int step, | ||
| 202 | int delta) | ||
| 203 | { | ||
| 204 | *scroll += delta; | ||
| 205 | while (*scroll > step) { | ||
| 206 | tickle_button(local, btinc); | ||
| 207 | *scroll -= step; | ||
| 208 | } | ||
| 209 | while (*scroll < -step) { | ||
| 210 | tickle_button(local, btdec); | ||
| 211 | *scroll += step; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | static void handle_gestures(LocalDevicePtr local, | ||
| 216 | const struct Gestures *gs, | ||
| 217 | const struct Capabilities *caps) | ||
| 218 | { | ||
| 219 | static int vscroll, hscroll, vswipe, hswipe, scale, rot; | ||
| 220 | int vscrollstep = 1 + vscroll_fraction * get_cap_ysize(caps); | ||
| 221 | int hscrollstep = 1 + hscroll_fraction * get_cap_xsize(caps); | ||
| 222 | int vswipestep = 1 + vswipe_fraction * get_cap_ysize(caps); | ||
| 223 | int hswipestep = 1 + hswipe_fraction * get_cap_xsize(caps); | ||
| 224 | int scalestep = 1 + scale_fraction * get_cap_xsize(caps); | ||
| 225 | int rotstep = 1 + rot_fraction * get_cap_xsize(caps); | ||
| 226 | int i; | ||
| 227 | if (!gs->same_fingers) { | ||
| 228 | vscroll = 0; | ||
| 229 | hscroll = 0; | ||
| 230 | vswipe = 0; | ||
| 231 | hswipe = 0; | ||
| 232 | } | ||
| 233 | for (i = 0; i < DIM_BUTTON; i++) { | ||
| 234 | if (GETBIT(gs->btmask, i)) { | ||
| 235 | xf86PostButtonEvent(local->dev, FALSE, | ||
| 236 | i + 1, GETBIT(gs->btdata, i), 0, 0); | ||
| 237 | TRACE2("button bit: %d %d\n", i, GETBIT(gs->btdata, i)); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | if (GETBIT(gs->type, GS_MOVE)) { | ||
| 241 | xf86PostMotionEvent(local->dev, 0, 0, 2, | ||
| 242 | gs->dx, gs->dy); | ||
| 243 | TRACE2("motion: %d %d\n", gs->dx, gs->dy); | ||
| 244 | } | ||
| 245 | if (GETBIT(gs->type, GS_VSCROLL)) { | ||
| 246 | button_scroll(local, 4, 5, &vscroll, vscrollstep, gs->dy); | ||
| 247 | TRACE1("vscroll: %d\n", gs->dy); | ||
| 248 | } | ||
| 249 | if (GETBIT(gs->type, GS_HSCROLL)) { | ||
| 250 | button_scroll(local, 6, 7, &hscroll, hscrollstep, gs->dx); | ||
| 251 | TRACE1("hscroll: %d\n", gs->dx); | ||
| 252 | } | ||
| 253 | if (GETBIT(gs->type, GS_VSWIPE)) { | ||
| 254 | button_scroll(local, 8, 9, &vswipe, vswipestep, gs->dy); | ||
| 255 | TRACE1("vswipe: %d\n", gs->dy); | ||
| 256 | } | ||
| 257 | if (GETBIT(gs->type, GS_HSWIPE)) { | ||
| 258 | button_scroll(local, 10, 11, &hswipe, hswipestep, gs->dx); | ||
| 259 | TRACE1("hswipe: %d\n", gs->dx); | ||
| 260 | } | ||
| 261 | if (GETBIT(gs->type, GS_SCALE)) { | ||
| 262 | button_scroll(local, 12, 13, &scale, scalestep, gs->scale); | ||
| 263 | TRACE1("scale: %d\n", gs->scale); | ||
| 264 | } | ||
| 265 | if (GETBIT(gs->type, GS_ROTATE)) { | ||
| 266 | button_scroll(local, 14, 15, &rot, rotstep, gs->rot); | ||
| 267 | TRACE1("rotate: %d\n", gs->rot); | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | /* called for each full received packet from the touchpad */ | ||
| 272 | static void read_input(LocalDevicePtr local) | ||
| 273 | { | ||
| 274 | struct Gestures gs; | ||
| 275 | struct MTouch *mt = local->private; | ||
| 276 | while (read_synchronized_event(mt, local->fd)) { | ||
| 277 | parse_event(mt); | ||
| 278 | extract_gestures(&gs, mt); | ||
| 279 | handle_gestures(local, &gs, &mt->caps); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | static Bool device_control(DeviceIntPtr dev, int mode) | ||
| 284 | { | ||
| 285 | LocalDevicePtr local = dev->public.devicePrivate; | ||
| 286 | switch (mode) { | ||
| 287 | case DEVICE_INIT: | ||
| 288 | xf86Msg(X_INFO, "device control: init\n"); | ||
| 289 | return device_init(dev, local); | ||
| 290 | case DEVICE_ON: | ||
| 291 | xf86Msg(X_INFO, "device control: on\n"); | ||
| 292 | return device_on(local); | ||
| 293 | case DEVICE_OFF: | ||
| 294 | xf86Msg(X_INFO, "device control: off\n"); | ||
| 295 | return device_off(local); | ||
| 296 | case DEVICE_CLOSE: | ||
| 297 | xf86Msg(X_INFO, "device control: close\n"); | ||
| 298 | return device_close(local); | ||
| 299 | default: | ||
| 300 | xf86Msg(X_INFO, "device control: default\n"); | ||
| 301 | return BadValue; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | |||
| 306 | static InputInfoPtr preinit(InputDriverPtr drv, IDevPtr dev, int flags) | ||
| 307 | { | ||
| 308 | struct MTouch *mt; | ||
| 309 | InputInfoPtr local = xf86AllocateInput(drv, 0); | ||
| 310 | if (!local) | ||
| 311 | goto error; | ||
| 312 | mt = xcalloc(1, sizeof(struct MTouch)); | ||
| 313 | if (!mt) | ||
| 314 | goto error; | ||
| 315 | |||
| 316 | local->name = dev->identifier; | ||
| 317 | local->type_name = XI_TOUCHPAD; | ||
| 318 | local->device_control = device_control; | ||
| 319 | local->read_input = read_input; | ||
| 320 | local->private = mt; | ||
| 321 | local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; | ||
| 322 | local->conf_idev = dev; | ||
| 323 | |||
| 324 | xf86CollectInputOptions(local, NULL, NULL); | ||
| 325 | /* xf86OptionListReport(local->options); */ | ||
| 326 | xf86ProcessCommonOptions(local, local->options); | ||
| 327 | |||
| 328 | local->flags |= XI86_CONFIGURED; | ||
| 329 | error: | ||
| 330 | return local; | ||
| 331 | } | ||
| 332 | |||
| 333 | static void uninit(InputDriverPtr drv, InputInfoPtr local, int flags) | ||
| 334 | { | ||
| 335 | xfree(local->private); | ||
| 336 | local->private = 0; | ||
| 337 | xf86DeleteInput(local, 0); | ||
| 338 | } | ||
| 339 | |||
| 340 | static InputDriverRec MULTITOUCH = { | ||
| 341 | 1, | ||
| 342 | "multitouch", | ||
| 343 | NULL, | ||
| 344 | preinit, | ||
| 345 | uninit, | ||
| 346 | NULL, | ||
| 347 | 0 | ||
| 348 | }; | ||
| 349 | |||
| 350 | static XF86ModuleVersionInfo VERSION = { | ||
| 351 | "multitouch", | ||
| 352 | MODULEVENDORSTRING, | ||
| 353 | MODINFOSTRING1, | ||
| 354 | MODINFOSTRING2, | ||
| 355 | XORG_VERSION_CURRENT, | ||
| 356 | 0, 1, 0, | ||
| 357 | ABI_CLASS_XINPUT, | ||
| 358 | ABI_XINPUT_VERSION, | ||
| 359 | MOD_CLASS_XINPUT, | ||
| 360 | {0, 0, 0, 0} | ||
| 361 | }; | ||
| 362 | |||
| 363 | static pointer setup(pointer module, pointer options, int *errmaj, int *errmin) | ||
| 364 | { | ||
| 365 | xf86AddInputDriver(&MULTITOUCH, module, 0); | ||
| 366 | return module; | ||
| 367 | } | ||
| 368 | |||
| 369 | XF86ModuleData multitouchModuleData = {&VERSION, &setup, NULL }; | ||
