Added button press and fixed issue with tracking active cursors
[xf86-input-tuio.git] / src / tuio.c
bloba39e9cf3b468f0db15e9fbe629a8daa6b5334e8c
1 /*
2 * Copyright (c) 2009 Ryan Huffman
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
22 * Authors:
23 * Ryan Huffman (ryanhuffman@gmail.com)
26 #include <unistd.h>
28 #include <xf86Xinput.h>
29 #include <X11/extensions/XIproto.h>
30 #include <X11/extensions/XInput2.h>
31 #include <xf86_OSlib.h>
33 #include "tuio.h"
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 /* Module Functions */
40 static pointer
41 TuioPlug(pointer, pointer, int *, int *);
43 static void
44 TuioUnplug(pointer);
46 /* Driver Functions */
47 static InputInfoPtr
48 TuioPreInit(InputDriverPtr, IDevPtr, int);
50 static void
51 TuioUnInit(InputDriverPtr, InputInfoPtr, int);
53 static void
54 TuioReadInput(InputInfoPtr);
56 static int
57 TuioControl(DeviceIntPtr, int);
59 /* Internal Functions */
60 static int
61 _tuio_init_buttons(DeviceIntPtr device);
63 static int
64 _tuio_init_axes(DeviceIntPtr device);
66 static int
67 _tuio_lo_cur2d_handle(const char *path,
68 const char *types,
69 lo_arg **argv,
70 int argc,
71 void *data,
72 void *user_data);
74 static void
75 lo_error(int num,
76 const char *msg,
77 const char *path);
79 /* Object list manipulation functions */
80 static ObjectPtr
81 _object_get(ObjectPtr head, int id);
83 static ObjectPtr
84 _object_insert(ObjectPtr head);
86 static void
87 _object_remove(ObjectPtr head, int id);
89 /* Driver information */
90 static XF86ModuleVersionInfo TuioVersionRec =
92 "tuio",
93 MODULEVENDORSTRING,
94 MODINFOSTRING1,
95 MODINFOSTRING2,
96 XORG_VERSION_CURRENT,
97 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
98 ABI_CLASS_XINPUT,
99 ABI_XINPUT_VERSION,
100 MOD_CLASS_XINPUT,
101 {0, 0, 0, 0}
104 _X_EXPORT InputDriverRec TUIO =
107 "tuio",
108 NULL,
109 TuioPreInit,
110 TuioUnInit,
111 NULL,
115 _X_EXPORT XF86ModuleData tuioModuleData =
117 &TuioVersionRec,
118 TuioPlug,
119 TuioUnplug
122 static pointer
123 TuioPlug(pointer module,
124 pointer options,
125 int *errmaj,
126 int *errmin)
128 xf86AddInputDriver(&TUIO, module, 0);
129 return module;
132 /* Remove this? */
133 static void
134 TuioUnplug(pointer p)
139 * Pre-initialization of new device
141 * TODO:
142 * - Parse configuration options
144 static InputInfoPtr
145 TuioPreInit(InputDriverPtr drv,
146 IDevPtr dev,
147 int flags)
149 InputInfoPtr pInfo;
150 TuioDevicePtr pTuio;
152 if (!(pInfo = xf86AllocateInput(drv, 0)))
153 return NULL;
155 /* The TuioDevicePtr will hold object and other
156 * information */
157 pTuio = xcalloc(1, sizeof(TuioDeviceRec));
158 if (!pTuio) {
159 pInfo->private = NULL;
160 xf86DeleteInput(pInfo, 0);
161 return NULL;
164 pTuio->list_head = xcalloc(1, sizeof(ObjectRec));
165 if (!pTuio->list_head) {
166 xfree(pTuio);
167 pInfo->private = NULL;
168 xf86DeleteInput(pInfo, 0);
169 return NULL;
171 pTuio->list_head->id = -1;
172 pTuio->list_head->next = NULL;
174 pInfo->private = pTuio;
176 /* Set up InputInfoPtr */
177 pInfo->name = xstrdup(dev->identifier);
178 pInfo->flags = 0;
179 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
180 pInfo->conf_idev = dev;
181 pInfo->read_input = TuioReadInput; /* Set callback */
182 pInfo->device_control = TuioControl; /* Set callback */
183 pInfo->switch_mode = NULL;
185 /* Process common device options */
186 xf86CollectInputOptions(pInfo, NULL, NULL);
187 xf86ProcessCommonOptions(pInfo, pInfo->options);
189 pInfo->flags |= XI86_OPEN_ON_INIT;
190 pInfo->flags |= XI86_CONFIGURED;
192 return pInfo;
196 * Clean up
198 static void
199 TuioUnInit(InputDriverPtr drv,
200 InputInfoPtr pInfo,
201 int flags)
203 TuioDevicePtr pTuio = pInfo->private;
205 xfree(pTuio);
206 xf86DeleteInput(pInfo, 0);
210 * Handle new data on the socket
212 static void
213 TuioReadInput(InputInfoPtr pInfo)
215 TuioDevicePtr pTuio = pInfo->private;
216 ObjectPtr head = pTuio->list_head;
217 ObjectPtr obj = head->next;
218 ObjectPtr objtemp;
220 while(xf86WaitForInput(pInfo->fd, 0) > 0)
222 /* The handler will set this flag if anything was processed */
223 pTuio->processed = 0;
225 /* liblo will receive a message and call the appropriate
226 * handlers (i.e. _tuio_lo_cur2d_hande()) */
227 lo_server_recv_noblock(pTuio->server, 0);
229 /* During the processing of the previous message/bundle,
230 * any "active" messages will be handled by flagging
231 * the listed object ids. Now that processing is done,
232 * remove any dead object ids. */
233 if (pTuio->processed) {
234 while (obj != NULL) {
235 if (!obj->alive) {
236 objtemp = obj->next;
237 _object_remove(head, obj->id);
238 obj = objtemp;
239 xf86PostButtonEvent(pInfo->dev, TRUE, 1, TRUE, 0, 0);
240 } else {
241 obj->alive = 0; /* Reset for next message */
242 obj = obj->next;
250 * Handle device state changes
252 static int
253 TuioControl(DeviceIntPtr device,
254 int what)
256 InputInfoPtr pInfo = device->public.devicePrivate;
257 TuioDevicePtr pTuio = pInfo->private;
259 switch (what)
261 case DEVICE_INIT:
262 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
263 _tuio_init_buttons(device);
264 _tuio_init_axes(device);
265 break;
267 case DEVICE_ON: /* Open device socket and start listening! */
268 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
269 if (device->public.on) /* already on! */
270 break;
272 /* Setup server */
273 pTuio->server = lo_server_new_with_proto("3333", LO_UDP, lo_error);
274 if (pTuio->server == NULL) {
275 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
276 pInfo->name);
277 return BadAlloc;
280 /* Register to receive all /tuio/2Dcur messages */
281 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
282 _tuio_lo_cur2d_handle, pInfo);
284 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
285 xf86Msg(X_INFO, "%s: Socket = %i\n", pInfo->name, pInfo->fd);
287 xf86FlushInput(pInfo->fd);
288 xf86AddEnabledDevice(pInfo);
289 device->public.on = TRUE;
290 break;
292 case DEVICE_OFF:
293 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
294 if (!device->public.on)
295 break;
297 xf86RemoveEnabledDevice(pInfo);
299 lo_server_free(pTuio->server);
300 pInfo->fd = -1;
301 device->public.on = FALSE;
302 break;
304 case DEVICE_CLOSE:
305 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
307 xfree(pTuio);
308 break;
311 return Success;
314 static int
315 _tuio_create_master() {
316 //XICreateMasterInfo ci;
317 //unsigned int blobid;
318 //char cur_name[21]; /* Max len: 20 char + \0 */
320 //sprintf(cur_name, "tuio_blob_%u", blobid);
322 //c.type = XICreateMaster;
323 //c.name = cur_name;
327 * Handles OSC messages in the /tuio/2Dcur address space
329 static int
330 _tuio_lo_cur2d_handle(const char *path,
331 const char *types,
332 lo_arg **argv,
333 int argc,
334 void *data,
335 void *user_data)
337 InputInfoPtr pInfo = user_data;
338 TuioDevicePtr pTuio = pInfo->private;
339 ObjectPtr head = pTuio->list_head;
340 ObjectPtr obj, objtemp;
341 int valuators[2];
342 int i;
344 /* Flag as being processed, used in TuioReadInput() */
345 pTuio->processed = 1;
347 /* Parse message type */
348 /* Set message type: */
349 if (strcmp(argv[0], "set") == 0) {
350 obj = _object_get(head, argv[1]->i);
351 if(obj == NULL) {
352 obj = _object_insert(head);
353 obj->id = argv[1]->i;
354 xf86PostButtonEvent(pInfo->dev, TRUE, 1, TRUE, 0, 0);
357 obj->x = argv[2]->f;
358 obj->y = argv[3]->f;
360 /* OKAY FOR NOW, MAYBE UPDATE */
361 valuators[0] = obj->x * 0x7FFFFFFF;
362 valuators[1] = obj->y * 0x7FFFFFFF;
364 xf86PostMotionEventP(pInfo->dev,
365 TRUE, /* is_absolute */
366 0, /* first_valuator */
367 2, /* num_valuators */
368 valuators);
370 } else if (strcmp(argv[0], "alive") == 0) {
371 obj = head->next;
372 while (obj != NULL) {
373 for (i=1; i<argc; i++) {
374 if (argv[i]->i == obj->id) {
375 obj->alive = 1;
376 break;
379 obj = obj->next;
382 } else if (strcmp(argv[0], "fseq") == 0) {
383 pTuio->fseq_old = pTuio->fseq_new;
384 pTuio->fseq_new = argv[1]->i;
387 return 0;
391 * liblo error handler
393 static void
394 lo_error(int num,
395 const char *msg,
396 const char *path)
398 xf86Msg(X_ERROR, "liblo: %s\n", msg);
402 * Retrieves an object from a list based on its id. Returns NULL if
403 * not found.
405 static ObjectPtr
406 _object_get(ObjectPtr head, int id) {
407 ObjectPtr obj = head->next;
409 while (obj != NULL && obj->id != id) {
410 obj = obj->next;
413 return obj;
417 * Allocates and inserts a new object at the beginning of a list.
418 * Pointer to the new object is returned.
419 * Doesn't check for duplicate ids, so call _object_get() beforehand
420 * to make sure it doesn't exist already!!
422 * @return ptr to new object
424 static ObjectPtr
425 _object_insert(ObjectPtr head) {
426 ObjectPtr obj = xcalloc(1, sizeof(ObjectRec));
427 obj->next = head->next;
428 head->next = obj;
429 return obj;
433 * Removes an object from a list. It is assumed that the object
434 * is in the list
436 static void
437 _object_remove(ObjectPtr head, int id) {
438 ObjectPtr obj = head;
439 ObjectPtr objtmp;
441 while (obj->next != NULL) {
442 if (obj->next->id == id) {
443 objtmp = obj->next;
444 obj->next = objtmp->next;
445 xfree(objtmp);
446 break;
448 obj = obj->next;
453 * Init the button map device. We only use one button.
455 static int
456 _tuio_init_buttons(DeviceIntPtr device)
458 InputInfoPtr pInfo = device->public.devicePrivate;
459 CARD8 *map;
460 Atom *labels;
461 const int num_buttons = 1; /* left-click */
462 int ret = Success;
463 int i;
465 map = xcalloc(num_buttons, sizeof(CARD8));
466 labels = xcalloc(num_buttons, sizeof(Atom));
468 for (i = 0; i < num_buttons; i++)
469 map[i] = i;
471 if (!InitButtonClassDeviceStruct(device, num_buttons,
472 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
473 labels,
474 #endif
475 map)) {
476 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
477 ret = BadAlloc;
480 xfree(labels);
481 xfree(map);
482 return ret;
486 * Init valuators for device, use x/y coordinates.
488 static int
489 _tuio_init_axes(DeviceIntPtr device)
491 InputInfoPtr pInfo = device->public.devicePrivate;
492 int i;
493 const int num_axes = 2;
494 Atom *atoms;
496 atoms = xcalloc(2, sizeof(Atom));
498 if (!InitValuatorClassDeviceStruct(device,
499 num_axes,
500 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
501 atoms,
502 #endif
503 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
504 GetMotionHistory,
505 #endif
506 GetMotionHistorySize(),
508 return BadAlloc;
510 /* Use absolute mode. Currently, TUIO coords are mapped to the
511 * full screen area */
512 pInfo->dev->valuator->mode = Absolute;
513 if (!InitAbsoluteClassDeviceStruct(device))
514 return BadAlloc;
516 for (i = 0; i < num_axes; i++)
518 xf86InitValuatorAxisStruct(device, i,
519 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
520 atoms[i],
521 #endif
522 0, 0x7FFFFFFF, 1, 1, 1);
523 xf86InitValuatorDefaults(device, i);
525 return Success;