1/* Written for XI1 by Nikolas Doerfler <doerflen@in.tum.de> (c) 2008 *
2 * Rewritten for XI2 by Florian Echtler <echtler@in.tum.de> (c) 2009 */
3
4#include <GL/freeglut.h>
5
6#include "../fg_internal.h"
7
8#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
9
10#include <errno.h>
11#include <stdarg.h>
12
13#include <X11/Xlib.h>
14#include <X11/extensions/XInput2.h>
15
16/* convert the XInput button state mask to the regular X mouse event button mask */
17#define BUTTON_MASK(xistate) ((xistate) << 8)
18
19/* import function from fg_main.c */
20extern int fgPlatformGetModifiers( int state );
21
22/* extension opcode for XInput */
23int xi_opcode = -1;
24
25/**
26 * \brief Sets window up for XI2 events.
27 */
28void fgRegisterDevices( Display* dpy, Window* win ) {
29
30 XIEventMask mask;
31 unsigned char flags[2] = { 0, 0 };
32 int event, error;
33
34 /*Display* dpy = fgDisplay.pDisplay.Display;
35 Window* win = glutGetXWindow();*/
36
37 /* get XInput extension opcode */
38 if (!XQueryExtension( dpy, "XInputExtension", &xi_opcode, &event, &error )) { xi_opcode = -1; }
39
40 /* Select for motion events */
41 mask.deviceid = XIAllMasterDevices;
42 mask.mask_len = 2;
43 mask.mask = flags;
44
45 XISetMask(mask.mask, XI_Enter);
46 XISetMask(mask.mask, XI_Motion);
47 XISetMask(mask.mask, XI_ButtonPress);
48 XISetMask(mask.mask, XI_ButtonRelease);
49 XISetMask(mask.mask, XI_Leave);
50 /*XISetMask(mask.mask, XI_KeyPress);
51 XISetMask(mask.mask, XI_KeyRelease);
52 XISetMask(mask.mask, XI_DeviceChanged);
53 XISetMask(mask.mask, XI_RawEvent);
54 XISetMask(mask.mask, XI_FocusIn);
55 XISetMask(mask.mask, XI_FocusOut);
56 XISetMask(mask.mask, XI_HierarchyChanged);*/
57
58 XISelectEvents( dpy, *win, &mask, 1 );
59}
60
61
62void fgPrintXILeaveEvent(XILeaveEvent* event)
63{
64 char* mode = "";
65 char* detail = "";
66 int i;
67
68 printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n",
69 event->root, event->event, event->child);
70 switch(event->mode)
71 {
72 case NotifyNormal: mode = "NotifyNormal"; break;
73 case NotifyGrab: mode = "NotifyGrab"; break;
74 case NotifyUngrab: mode = "NotifyUngrab"; break;
75 case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break;
76 }
77 switch (event->detail)
78 {
79 case NotifyAncestor: detail = "NotifyAncestor"; break;
80 case NotifyVirtual: detail = "NotifyVirtual"; break;
81 case NotifyInferior: detail = "NotifyInferior"; break;
82 case NotifyNonlinear: detail = "NotifyNonlinear"; break;
83 case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break;
84 case NotifyPointer: detail = "NotifyPointer"; break;
85 case NotifyPointerRoot: detail = "NotifyPointerRoot"; break;
86 case NotifyDetailNone: detail = "NotifyDetailNone"; break;
87 }
88 printf(" mode: %s (detail %s)\n", mode, detail);
89 printf(" flags: %s %s\n", event->focus ? "[focus]" : "",
90 event->same_screen ? "[same screen]" : "");
91 printf(" buttons:");
92 for (i = 0; i < event->buttons.mask_len * 8; i++)
93 if (XIMaskIsSet(event->buttons.mask, i))
94 printf(" %d", i);
95 printf("\n");
96
97 printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n",
98 event->mods.locked, event->mods.latched,
99 event->mods.base);
100 printf(" group: locked 0x%x latched 0x%x base 0x%x\n",
101 event->group.locked, event->group.latched,
102 event->group.base);
103
104 printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y);
105 printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y);
106
107}
108
109
110void fgPrintXIDeviceEvent(XIDeviceEvent* event)
111{
112 double *val;
113 int i;
114
115 printf(" device: %d (%d)\n", event->deviceid, event->sourceid);
116 printf(" detail: %d\n", event->detail);
117 printf(" buttons:");
118 for (i = 0; i < event->buttons.mask_len * 8; i++)
119 if (XIMaskIsSet(event->buttons.mask, i))
120 printf(" %d", i);
121 printf("\n");
122
123 printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n",
124 event->mods.locked, event->mods.latched,
125 event->mods.base);
126 printf(" group: locked 0x%x latched 0x%x base 0x%x\n",
127 event->group.locked, event->group.latched,
128 event->group.base);
129 printf(" valuators:");
130
131 val = event->valuators.values;
132 for (i = 0; i < event->valuators.mask_len * 8; i++)
133 if (XIMaskIsSet(event->valuators.mask, i))
134 printf(" %d: %.2f", i, *val++);
135 printf("\n");
136
137 printf(" windows: root 0x%lx event 0x%lx child 0x%ld\n",
138 event->root, event->event, event->child);
139 printf(" root x/y: %.2f / %.2f\n", event->root_x, event->root_y);
140 printf(" event x/y: %.2f / %.2f\n", event->event_x, event->event_y);
141
142}
143
144/**
145 * \brief This function is called when an Extension Event is received
146 * and calls the corresponding callback functions for these events.
147 */
148void fgHandleExtensionEvents( XEvent* base_ev )
149{
150 XEvent std_ev; /* standard single-pointer event to be added to the event queue */
151 int i, button = 0;
152 XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie);
153
154 /* initialize the generic fields from base_ev */
155 std_ev.xany = base_ev->xany;
156
157 if ( XGetEventData( fgDisplay.pDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) {
158
159 XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data);
160 XIEnterEvent *evcross;
161 /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/
162
163 SFG_Window* window = fgWindowByHandle( event->event );
164 if (!window) return;
165
166 switch (cookie->evtype) {
167 case XI_Enter:
168 case XI_Leave:
169 evcross = (XIEnterEvent*)event;
170
171 fgState.Modifiers = fgPlatformGetModifiers( evcross->mods.base );
172 INVOKE_WCB( *window, MultiEntry, (
173 event->deviceid,
174 (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT)
175 ));
176 #if _DEBUG
177 fgPrintXILeaveEvent((XILeaveEvent*)event);
178 #endif
179
180 /* Also process the standard crossing event */
181 std_ev.type = evcross->evtype == XI_Enter ? EnterNotify : LeaveNotify;
182 std_ev.xcrossing.window = evcross->event;
183 std_ev.xcrossing.root = evcross->root;
184 std_ev.xcrossing.subwindow = evcross->child;
185 std_ev.xcrossing.x = evcross->event_x;
186 std_ev.xcrossing.y = evcross->event_y;
187 std_ev.xcrossing.x_root = evcross->root_x;
188 std_ev.xcrossing.y_root = evcross->root_y;
189 std_ev.xcrossing.mode = evcross->mode;
190 std_ev.xcrossing.detail = evcross->detail;
191 std_ev.xcrossing.same_screen = evcross->same_screen;
192 std_ev.xcrossing.focus = evcross->focus;
193 std_ev.xcrossing.state = BUTTON_MASK(*(unsigned int*)evcross->buttons.mask);
194
195 XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
196 break;
197
198 case XI_ButtonPress:
199 case XI_ButtonRelease:
200 fgState.Modifiers = fgPlatformGetModifiers( event->mods.base );
201 INVOKE_WCB( *window, MultiButton, (
202 event->deviceid,
203 event->event_x,
204 event->event_y,
205 event->detail-1,
206 (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP)
207 ));
208
209 /* Also process the standard button event */
210 std_ev.type = event->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
211 std_ev.xbutton.window = event->event;
212 std_ev.xbutton.root = event->root;
213 std_ev.xbutton.subwindow = event->child;
214 std_ev.xbutton.x = event->event_x;
215 std_ev.xbutton.y = event->event_y;
216 std_ev.xbutton.x_root = event->root_x;
217 std_ev.xbutton.y_root = event->root_y;
218 std_ev.xbutton.state = event->mods.base;
219 std_ev.xbutton.button = event->detail;
220
221 XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
222 break;
223
224 case XI_Motion:
225 fgState.Modifiers = fgPlatformGetModifiers( event->mods.base );
226 for (i = 0; i < event->buttons.mask_len; i++) {
227 if (event->buttons.mask[i]) {
228 button = 1;
229 }
230 }
231 if (button) {
232 INVOKE_WCB( *window, MultiMotion, ( event->deviceid, event->event_x, event->event_y ) );
233 } else {
234 INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) );
235 }
236 #if _DEBUG
237 fgPrintXIDeviceEvent(event);
238 #endif
239
240 /* Also process the standard motion event */
241 std_ev.type = MotionNotify;
242 std_ev.xmotion.window = event->event;
243 std_ev.xmotion.root = event->root;
244 std_ev.xmotion.subwindow = event->child;
245 std_ev.xmotion.time = event->time;
246 std_ev.xmotion.x = event->event_x;
247 std_ev.xmotion.y = event->event_y;
248 std_ev.xmotion.x_root = event->root_x;
249 std_ev.xmotion.y_root = event->root_y;
250 std_ev.xmotion.state = BUTTON_MASK(*(unsigned int*)event->buttons.mask);
251 std_ev.xmotion.is_hint = NotifyNormal;
252
253 XPutBackEvent(fgDisplay.pDisplay.Display, &std_ev);
254 break;
255
256 default:
257 #if _DEBUG
258 fgWarning( "Unknown XI2 device event:" );
259 fgPrintXIDeviceEvent( event );
260 #endif
261 break;
262 }
263 fgState.Modifiers = INVALID_MODIFIERS;
264 }
265 XFreeEventData( fgDisplay.pDisplay.Display, cookie );
266}
267
268#endif
269