2 * Copyright (c) 2009 Ryan Huffman
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
23 * Ryan Huffman (ryanhuffman@gmail.com)
28 #include <xf86Xinput.h>
29 #include <X11/extensions/XIproto.h>
30 #include <X11/extensions/XInput2.h>
31 #include <xf86_OSlib.h>
39 /* Module Functions */
41 TuioPlug(pointer
, pointer
, int *, int *);
46 /* Driver Functions */
48 TuioPreInit(InputDriverPtr
, IDevPtr
, int);
51 TuioUnInit(InputDriverPtr
, InputInfoPtr
, int);
54 TuioReadInput(InputInfoPtr
);
57 TuioControl(DeviceIntPtr
, int);
59 /* Internal Functions */
61 _tuio_init_buttons(DeviceIntPtr device
);
64 _tuio_init_axes(DeviceIntPtr device
);
67 _tuio_lo_cur2d_handle(const char *path
,
79 /* Object list manipulation functions */
81 _object_get(ObjectPtr head
, int id
);
84 _object_insert(ObjectPtr head
);
87 _object_remove(ObjectPtr head
, int id
);
89 /* Driver information */
90 static XF86ModuleVersionInfo TuioVersionRec
=
97 PACKAGE_VERSION_MAJOR
, PACKAGE_VERSION_MINOR
, PACKAGE_VERSION_PATCHLEVEL
,
104 _X_EXPORT InputDriverRec TUIO
=
115 _X_EXPORT XF86ModuleData tuioModuleData
=
123 TuioPlug(pointer module
,
128 xf86AddInputDriver(&TUIO
, module
, 0);
134 TuioUnplug(pointer p
)
139 * Pre-initialization of new device
142 * - Parse configuration options
145 TuioPreInit(InputDriverPtr drv
,
152 if (!(pInfo
= xf86AllocateInput(drv
, 0)))
155 /* The TuioDevicePtr will hold object and other
157 pTuio
= xcalloc(1, sizeof(TuioDeviceRec
));
159 pInfo
->private = NULL
;
160 xf86DeleteInput(pInfo
, 0);
164 pTuio
->list_head
= xcalloc(1, sizeof(ObjectRec
));
165 if (!pTuio
->list_head
) {
167 pInfo
->private = NULL
;
168 xf86DeleteInput(pInfo
, 0);
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
);
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
;
199 TuioUnInit(InputDriverPtr drv
,
203 TuioDevicePtr pTuio
= pInfo
->private;
206 xf86DeleteInput(pInfo
, 0);
210 * Handle new data on the socket
213 TuioReadInput(InputInfoPtr pInfo
)
215 TuioDevicePtr pTuio
= pInfo
->private;
216 ObjectPtr head
= pTuio
->list_head
;
217 ObjectPtr obj
= head
->next
;
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
) {
237 _object_remove(head
, obj
->id
);
239 xf86PostButtonEvent(pInfo
->dev
, TRUE
, 1, TRUE
, 0, 0);
241 obj
->alive
= 0; /* Reset for next message */
250 * Handle device state changes
253 TuioControl(DeviceIntPtr device
,
256 InputInfoPtr pInfo
= device
->public.devicePrivate
;
257 TuioDevicePtr pTuio
= pInfo
->private;
262 xf86Msg(X_INFO
, "%s: Init\n", pInfo
->name
);
263 _tuio_init_buttons(device
);
264 _tuio_init_axes(device
);
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! */
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",
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
;
293 xf86Msg(X_INFO
, "%s: Off\n", pInfo
->name
);
294 if (!device
->public.on
)
297 xf86RemoveEnabledDevice(pInfo
);
299 lo_server_free(pTuio
->server
);
301 device
->public.on
= FALSE
;
305 xf86Msg(X_INFO
, "%s: Close\n", pInfo
->name
);
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;
327 * Handles OSC messages in the /tuio/2Dcur address space
330 _tuio_lo_cur2d_handle(const char *path
,
337 InputInfoPtr pInfo
= user_data
;
338 TuioDevicePtr pTuio
= pInfo
->private;
339 ObjectPtr head
= pTuio
->list_head
;
340 ObjectPtr obj
, objtemp
;
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
);
352 obj
= _object_insert(head
);
353 obj
->id
= argv
[1]->i
;
354 xf86PostButtonEvent(pInfo
->dev
, TRUE
, 1, TRUE
, 0, 0);
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 */
370 } else if (strcmp(argv
[0], "alive") == 0) {
372 while (obj
!= NULL
) {
373 for (i
=1; i
<argc
; i
++) {
374 if (argv
[i
]->i
== obj
->id
) {
382 } else if (strcmp(argv
[0], "fseq") == 0) {
383 pTuio
->fseq_old
= pTuio
->fseq_new
;
384 pTuio
->fseq_new
= argv
[1]->i
;
391 * liblo error handler
398 xf86Msg(X_ERROR
, "liblo: %s\n", msg
);
402 * Retrieves an object from a list based on its id. Returns NULL if
406 _object_get(ObjectPtr head
, int id
) {
407 ObjectPtr obj
= head
->next
;
409 while (obj
!= NULL
&& obj
->id
!= id
) {
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
425 _object_insert(ObjectPtr head
) {
426 ObjectPtr obj
= xcalloc(1, sizeof(ObjectRec
));
427 obj
->next
= head
->next
;
433 * Removes an object from a list. It is assumed that the object
437 _object_remove(ObjectPtr head
, int id
) {
438 ObjectPtr obj
= head
;
441 while (obj
->next
!= NULL
) {
442 if (obj
->next
->id
== id
) {
444 obj
->next
= objtmp
->next
;
453 * Init the button map device. We only use one button.
456 _tuio_init_buttons(DeviceIntPtr device
)
458 InputInfoPtr pInfo
= device
->public.devicePrivate
;
461 const int num_buttons
= 1; /* left-click */
465 map
= xcalloc(num_buttons
, sizeof(CARD8
));
466 labels
= xcalloc(num_buttons
, sizeof(Atom
));
468 for (i
= 0; i
< num_buttons
; i
++)
471 if (!InitButtonClassDeviceStruct(device
, num_buttons
,
472 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
476 xf86Msg(X_ERROR
, "%s: Failed to register buttons.\n", pInfo
->name
);
486 * Init valuators for device, use x/y coordinates.
489 _tuio_init_axes(DeviceIntPtr device
)
491 InputInfoPtr pInfo
= device
->public.devicePrivate
;
493 const int num_axes
= 2;
496 atoms
= xcalloc(2, sizeof(Atom
));
498 if (!InitValuatorClassDeviceStruct(device
,
500 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
503 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
506 GetMotionHistorySize(),
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
))
516 for (i
= 0; i
< num_axes
; i
++)
518 xf86InitValuatorAxisStruct(device
, i
,
519 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
522 0, 0x7FFFFFFF, 1, 1, 1);
523 xf86InitValuatorDefaults(device
, i
);