cdc3abe1c0283e89b6137d2c80fbf7f5e9b8685d
[freeglut] / src / x11 / fg_xinput_x11.c
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 */
20 extern int fgPlatformGetModifiers( int state );
21
22 /* extension opcode for XInput */
23 int xi_opcode = -1;
24
25 /**
26  * \brief Sets window up for XI2 events.
27  */
28 void 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
62 void 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
110 void 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  */
148 void 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