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 /* liblo will receive a message and call the appropriate
223 * handlers (i.e. _tuio_lo_cur2d_hande())
224 * If nothing is found (this SHOULDN'T happen, but if it did,
225 * all the objects would be deleted), just return */
226 if(!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 while (obj
!= NULL
) {
236 _object_remove(head
, obj
->id
);
239 obj
->alive
= 0; /* Reset for next message */
247 * Handle device state changes
250 TuioControl(DeviceIntPtr device
,
253 InputInfoPtr pInfo
= device
->public.devicePrivate
;
254 TuioDevicePtr pTuio
= pInfo
->private;
259 xf86Msg(X_INFO
, "%s: Init\n", pInfo
->name
);
260 _tuio_init_buttons(device
);
261 _tuio_init_axes(device
);
264 case DEVICE_ON
: /* Open device socket and start listening! */
265 xf86Msg(X_INFO
, "%s: On.\n", pInfo
->name
);
266 if (device
->public.on
) /* already on! */
270 pTuio
->server
= lo_server_new_with_proto("3333", LO_UDP
, lo_error
);
271 if (pTuio
->server
== NULL
) {
272 xf86Msg(X_ERROR
, "%s: Error allocating new lo_server\n",
277 /* Register to receive all /tuio/2Dcur messages */
278 lo_server_add_method(pTuio
->server
, "/tuio/2Dcur", NULL
,
279 _tuio_lo_cur2d_handle
, pInfo
);
281 pInfo
->fd
= lo_server_get_socket_fd(pTuio
->server
);
282 xf86Msg(X_INFO
, "%s: Socket = %i\n", pInfo
->name
, pInfo
->fd
);
284 xf86FlushInput(pInfo
->fd
);
285 xf86AddEnabledDevice(pInfo
);
286 device
->public.on
= TRUE
;
290 xf86Msg(X_INFO
, "%s: Off\n", pInfo
->name
);
291 if (!device
->public.on
)
294 xf86RemoveEnabledDevice(pInfo
);
296 lo_server_free(pTuio
->server
);
298 device
->public.on
= FALSE
;
302 xf86Msg(X_INFO
, "%s: Close\n", pInfo
->name
);
312 _tuio_create_master() {
313 //XICreateMasterInfo ci;
314 //unsigned int blobid;
315 //char cur_name[21]; /* Max len: 20 char + \0 */
317 //sprintf(cur_name, "tuio_blob_%u", blobid);
319 //c.type = XICreateMaster;
324 * Handles OSC messages in the /tuio/2Dcur address space
327 _tuio_lo_cur2d_handle(const char *path
,
334 InputInfoPtr pInfo
= user_data
;
335 TuioDevicePtr pTuio
= pInfo
->private;
336 ObjectPtr head
= pTuio
->list_head
;
337 ObjectPtr obj
, objtemp
;
342 xf86Msg(X_ERROR
, "%s: \n", pInfo
->name
);
346 /* 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
;
359 /* OKAY FOR NOW, MAYBE UPDATE */
360 valuators
[0] = obj
->x
* 0x7FFFFFFF;
361 valuators
[1] = obj
->y
* 0x7FFFFFFF;
363 xf86PostMotionEventP(pInfo
->dev
,
364 TRUE
, /* is_absolute */
365 0, /* first_valuator */
366 2, /* num_valuators */
369 } else if (strcmp(argv
[0], "alive") == 0) {
371 while (obj
!= NULL
) {
372 for (i
=1; i
<argc
; i
++) {
373 if (argv
[i
]->i
== obj
->id
) {
381 } else if (strcmp(argv
[0], "fseq") == 0) {
382 pTuio
->fseq_old
= pTuio
->fseq_new
;
383 pTuio
->fseq_new
= argv
[1]->i
;
390 * liblo error handler
397 xf86Msg(X_ERROR
, "liblo: %s\n", msg
);
401 * Retrieves an object from a list based on its id. Returns NULL if
405 _object_get(ObjectPtr head
, int id
) {
406 ObjectPtr obj
= head
->next
;
408 while (obj
!= NULL
&& obj
->id
!= id
) {
416 * Allocates and inserts a new object at the beginning of a list.
417 * Pointer to the new object is returned.
418 * Doesn't check for duplicate ids, so call _object_get() beforehand
419 * to make sure it doesn't exist already!!
421 * @return ptr to new object
424 _object_insert(ObjectPtr head
) {
425 ObjectPtr obj
= xcalloc(1, sizeof(ObjectRec
));
426 obj
->next
= head
->next
;
432 * Removes an object from a list. It is assumed that the object
436 _object_remove(ObjectPtr head
, int id
) {
437 ObjectPtr obj
= head
;
440 while (obj
->next
!= NULL
) {
441 if (obj
->next
->id
== id
) {
443 obj
->next
= objtmp
->next
;
452 * Init the button map device. We only use one button.
455 _tuio_init_buttons(DeviceIntPtr device
)
457 InputInfoPtr pInfo
= device
->public.devicePrivate
;
460 const int num_buttons
= 1; /* left-click */
464 map
= xcalloc(num_buttons
, sizeof(CARD8
));
465 labels
= xcalloc(num_buttons
, sizeof(Atom
));
467 for (i
= 0; i
< num_buttons
; i
++)
470 if (!InitButtonClassDeviceStruct(device
, num_buttons
,
471 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
475 xf86Msg(X_ERROR
, "%s: Failed to register buttons.\n", pInfo
->name
);
485 * Init valuators for device, use x/y coordinates.
488 _tuio_init_axes(DeviceIntPtr device
)
490 InputInfoPtr pInfo
= device
->public.devicePrivate
;
492 const int num_axes
= 2;
495 atoms
= xcalloc(2, sizeof(Atom
));
497 if (!InitValuatorClassDeviceStruct(device
,
499 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
502 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
505 GetMotionHistorySize(),
509 /* Use absolute mode. Currently, TUIO coords are mapped to the
510 * full screen area */
511 pInfo
->dev
->valuator
->mode
= Absolute
;
512 if (!InitAbsoluteClassDeviceStruct(device
))
515 for (i
= 0; i
< num_axes
; i
++)
517 xf86InitValuatorAxisStruct(device
, i
,
518 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
521 0, 0x7FFFFFFF, 1, 1, 1);
522 xf86InitValuatorDefaults(device
, i
);