1 /* gcc -o part2 `pkg-config --cflags --libs xi` part2.c */
7 #include <X11/extensions/XInput2.h>
9 #define MD_PREFIX "TUIO "
11 typedef struct _attach_info
{
12 struct _attach_info
*next
;
15 } AttachInfo
, *AttachInfoPtr
;
17 static AttachInfo ais
;
20 * Creates a new master device.
22 int create_master(Display
* dpy
, char* name
)
31 return XIChangeHierarchy(dpy
, (XIAnyHierarchyChangeInfo
*)&c
, 1);
35 * Attaches a slave device to a master device.
37 int change_attachment(Display
* dpy
, int slaveid
, int masterid
)
41 c
.type
= XIAttachSlave
;
43 c
.new_master
= masterid
;
45 return XIChangeHierarchy(dpy
, (XIAnyHierarchyChangeInfo
*)&c
, 1);
49 * Listens for the creation of slave and master devices. When a new slave
50 * device is found, a new master device will be created and attached to
51 * when the message for the new master device comes back around.
53 void listen(Display
*dpy
, int xi_opcode
)
56 unsigned char hmask
[2] = { 0, 0 };
57 char *m_name
, *s_name
;
63 m_cur
= XCreateFontCursor(dpy
, 88);
64 if (m_cur
== BadAlloc
|| m_cur
== BadValue
) {
65 printf("Unable to create cursor\n");
68 evmask_h
.mask
= hmask
;
69 evmask_h
.mask_len
= sizeof(hmask
);
70 evmask_h
.deviceid
= XIAllDevices
;
71 XISetMask(hmask
, XI_HierarchyChanged
);
74 XISelectEvents(dpy
, DefaultRootWindow(dpy
), &evmask_h
, 1);
77 XNextEvent(dpy
, (XIEvent
*)&ev
);
78 if (ev
.type
!= GenericEvent
||
79 ev
.extension
!= xi_opcode
)
82 if (ev
.evtype
== XI_HierarchyChanged
) {
84 XIHierarchyEvent
*event
= (XIHierarchyEvent
*)&ev
;
85 printf("Hierarchy Event.\n");
87 /* Look for slave or masters added */
88 if (event
->flags
& XISlaveAdded
) {
89 printf("Slave added\n");
90 for (i
=0; i
< event
->num_info
; i
++) {
91 if(event
->info
[i
].flags
& XISlaveAdded
) {
92 s_name
= XIQueryDevice(dpy
, event
->info
[i
].deviceid
, &num_devices
)->name
;
94 /* This is a hack. Xtst slave devices are created and
95 * attached to each new master device. If we were to
96 * actually create a new master device for this device
97 * we would end up with a recurring creation of
98 * master devices and slave devices. */
99 if (strstr(s_name
, "Xtst")) continue;
101 asprintf(&m_name
, MD_PREFIX
"%s", s_name
);
102 create_master(dpy
, m_name
);
105 ai
= malloc(sizeof(AttachInfo
));
109 asprintf(&ai
->m_name
, MD_PREFIX
"%s pointer", s_name
);
110 ai
->slaveid
= event
->info
[i
].deviceid
;
113 } else if (event
->flags
& XIMasterAdded
) {
114 printf("Master added\n");
116 for (i
=0; i
< event
->num_info
; i
++) {
117 if(event
->info
[i
].flags
& XIMasterAdded
) {
119 m_name
= XIQueryDevice(dpy
, event
->info
[i
].deviceid
, &num_devices
)->name
;
123 if (strcmp(ai
->m_name
, m_name
) == 0) {
124 printf(" New Master: %d %s\n", event
->info
[i
].deviceid
,
126 change_attachment(dpy
, ai
->slaveid
, event
->info
[i
].deviceid
);
127 XIDefineCursor(dpy
, event
->info
[i
].deviceid
,
128 DefaultRootWindow(dpy
), m_cur
);
139 int main (int argc
, char **argv
)
142 int xi_opcode
, event
, error
;
149 dpy
= XOpenDisplay(NULL
);
151 printf("Failed to open display.\n");
155 /* Make sure the X Input extension is available */
156 if (!XQueryExtension(dpy
, "XInputExtension", &xi_opcode
, &event
, &error
)) {
157 printf("X Input extension not available.\n");
161 /* Check XI version, need 2.0 */
164 ret
= XIQueryVersion(dpy
, &major
, &minor
);
165 if (ret
== BadRequest
) {
166 printf("XInput 2.0 not supported. Server supports %i.%i.\n", major
, minor
);
170 listen(dpy
, xi_opcode
);