version 0.2.0
[expresskeys.git] / src-server / event_loop.c
1 /*
2  event_loop.c -- Support ExpressKeys & Touch Strips on a Wacom Intuos3 tablet.
3  
4  Copyright (C) 2005 - Mats Johannesson
5  
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21 #include "globals.h"
22
23 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24  Function waits perpetually for the X server to deliver information
25  about events from the input device. Receipt of an event that we've
26  registered for (button press/release and motion) triggers a good deal
27  of activity in a setup phase, after which we send the fake key press
28  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
29
30 int use_events(Display *display)
31 {
32
33         XClassHint *class_hint;
34
35         Window focus_window;
36         int focus_state;
37
38         Window root, parent;
39         Window *children;
40         unsigned int num_children;
41
42         struct program *p;
43         int in_list;
44
45         int elder_rotation = 4097; /* Set the Touch Strip state histories to */
46         int old_rotation = 4097;   /* their max values. This is to ensure */
47         int elder_throttle = 4097; /* that no action is taken on the very */
48         int old_throttle = 4097;   /* first touch before a real history is */
49         int rotation;              /* recorded. Bottom is 4097. Top is 2 */
50         int throttle;
51
52         int i = 0;
53         int *button_index = 0;
54
55         XDeviceMotionEvent *motion;
56         XDeviceButtonEvent *button;
57
58         XEvent Event;
59
60         while(1) {
61
62                 XNextEvent(display, &Event);
63
64                 class_hint = XAllocClassHint(); /* Memory allocation. Free it later! */
65
66                 focus_window = None;
67                 in_list = 0;
68
69 /* Locate which window that currently has the focus and get its list of
70    related windows. Then pull its ClassHint into our allocated structure */
71
72                 XGetInputFocus(display, &focus_window, &focus_state);
73                 XQueryTree(display, focus_window, &root, &parent, &children, &num_children);
74                 XGetClassHint(display, focus_window, class_hint);
75
76 /* If the class hint (aka WM_CLASS) contains no class string we free the
77    allocated memory for each structure member and get the ClassHint of the
78    window parent, if it has one. Observe that we must skip the root window */
79
80                 if ((!class_hint->res_class) && (parent) && (focus_window != root)) {
81                         XFree(class_hint->res_class);
82                         XFree(class_hint->res_name);
83                         XGetClassHint(display, parent, class_hint);
84                 }
85
86 /* If the root window had the focus, or if the active window or its parent
87    had no class string at all, we use the top ("default") program definition
88    from the read in configuration file when evaluating the event. Otherwise
89    we start scanning for a match between the class strings in our list and
90    the found window class. Set a flag if a match is encountered */
91
92                 if ((focus_window == root) || (class_hint->res_class == NULL)) {
93                         p = external_list;
94                 } else {
95                         for (p = external_list; p < external_list + num_list; p++)
96                                 if (strcmp (class_hint->res_class, p->class_name) == 0) {
97                                         in_list = 1;
98                                         break;
99                                 }
100                         }
101
102 /* Any program not found in our configuration gets the "default" treatment */
103
104                 if (!in_list) {
105                         p = external_list;
106                 }
107
108 /* The allocated memory for the ClassHint structure, and each of its
109    members, must be freed here. Also, the call to XQueryTree to get a
110    list of related windows might have allocated memory for child entries.
111    It must be released as well */
112                 
113                 XFree(class_hint->res_class);
114                 XFree(class_hint->res_name);
115                 XFree(class_hint);
116                 if (children) XFree((char *)children);
117
118                 if (be_verbose) {
119                         fprintf(stderr, "PGR RUNNAME = %s\n", p->class_name);
120                 }
121
122 /* Finally start to look at the actual event. Touch Strips come first */
123
124                 if (Event.type == motion_type) {
125
126                         if (p->handle_touch) {
127
128                         motion = (XDeviceMotionEvent *) &Event;
129
130                                 rotation = motion->axis_data[3];
131                                 throttle = motion->axis_data[4];
132
133 /* As can be analyzed with Frederic Lepied's excellent xinput-1.2 program
134    the touch strip data comes in on axis 3 and 4 (left and right strips).
135    The pad device never uses x-axis [0], y-axis [1] or wheel [5]. The value
136    is always 0 there. The pressure [2], rotation [3] and throttle [4] all
137    rest with a value of 1. Touch strips send data about the finger position
138    in 13 steps. Furthest down is 4097 while the top is 2. Template:
139    4097, 2049, 1025, 513, 257, 129, 65, 33, 17, 9, 5, 3, 2. We don't care
140    about those numbers per se (for now at least ;-), but just stick them
141    in history buffers. The present value is then compared to an old and
142    an even older one to determine direction of the finger movement. Observe
143    that when we finally send a fake keypress, it has two parts - true and
144    false. It corresponds with a key press and a key release. Order is key ;-) */
145
146 /* Left Touch Strip */
147
148                                 if (rotation > 1) {
149                                         if ((rotation < old_rotation) && (old_rotation <= elder_rotation)) {
150                                                 if (p->l_touch_up) {
151                                                         XTestFakeKeyEvent(display, p->l_touch_up, True, CurrentTime);
152                                                         if (be_verbose) {
153                                                                 fprintf(stderr, "KEY LTCHUP = %d\n", p->l_touch_up);
154                                                         }
155                                                         if (p->l_touch_up_plus) {
156                                                                 XTestFakeKeyEvent(display, p->l_touch_up_plus, True, CurrentTime);
157                                                                 XTestFakeKeyEvent(display, p->l_touch_up_plus, False, CurrentTime);
158                                                                 if (be_verbose) {
159                                                                         fprintf(stderr, "KEY LTCHUP+ = %d\n", p->l_touch_up_plus);
160                                                                 }
161                                                         }
162                                                         XTestFakeKeyEvent(display, p->l_touch_up, False, CurrentTime);
163                                                 }
164                                         } else if ((rotation > old_rotation) && (old_rotation >= elder_rotation)) {
165                                                 if (p->l_touch_down) {
166                                                         XTestFakeKeyEvent(display, p->l_touch_down, True, CurrentTime);
167                                                         if (be_verbose) {
168                                                                 fprintf(stderr, "KEY LTCHDN = %d\n", p->l_touch_down);
169                                                         }
170                                                         if (p->l_touch_down_plus) {
171                                                                 XTestFakeKeyEvent(display, p->l_touch_down_plus, True, CurrentTime);
172                                                                 XTestFakeKeyEvent(display, p->l_touch_down_plus, False, CurrentTime);
173                                                                 if (be_verbose) {
174                                                                         fprintf(stderr, "KEY LTCHDN+ = %d\n", p->l_touch_down_plus);
175                                                                 }
176                                                         }
177                                                         XTestFakeKeyEvent(display, p->l_touch_down, False, CurrentTime);
178                                                 }
179                                         }
180                                 elder_rotation = old_rotation;
181                                 old_rotation = rotation;
182                                 }
183
184 /* Right Touch Strip */
185
186                                 if (throttle > 1) {
187                                         if ((throttle < old_throttle) && (old_throttle <= elder_throttle)) {
188                                                 if (p->r_touch_up) {
189                                                         XTestFakeKeyEvent(display, p->r_touch_up, True, CurrentTime);
190                                                         if (be_verbose) {
191                                                                 fprintf(stderr, "KEY RTCHUP = %d\n", p->r_touch_up);
192                                                         }
193                                                         if (p->r_touch_up_plus) {
194                                                                 XTestFakeKeyEvent(display, p->r_touch_up_plus, True, CurrentTime);
195                                                                 XTestFakeKeyEvent(display, p->r_touch_up_plus, False, CurrentTime);
196                                                                 if (be_verbose) {
197                                                                         fprintf(stderr, "KEY RTCHUP+ = %d\n", p->r_touch_up_plus);
198                                                                 }
199                                                         }
200                                                         XTestFakeKeyEvent(display, p->r_touch_up, False, CurrentTime);
201                                                 }
202                                         } else if ((throttle > old_throttle) && (old_throttle >= elder_throttle)) {
203                                                 if (p->r_touch_down) {
204                                                         XTestFakeKeyEvent(display, p->r_touch_down, True, CurrentTime);
205                                                         if (be_verbose) {
206                                                                 fprintf(stderr, "KEY RTCHDN = %d\n", p->r_touch_down);
207                                                         }
208                                                         if (p->r_touch_down_plus) {
209                                                                 XTestFakeKeyEvent(display, p->r_touch_down_plus, True, CurrentTime);
210                                                                 XTestFakeKeyEvent(display, p->r_touch_down_plus, False, CurrentTime);
211                                                                 if (be_verbose) {
212                                                                         fprintf(stderr, "KEY RTCHDN+ = %d\n", p->r_touch_down_plus);
213                                                                 }
214                                                         }
215                                                         XTestFakeKeyEvent(display, p->r_touch_down, False, CurrentTime);
216                                                 }
217                                         }
218                                 elder_throttle = old_throttle;
219                                 old_throttle = throttle;
220                                 }
221                         }
222                 }
223
224 /* Now see if the event concerned the pad buttons. Not much to talk about.
225    We follow the configuration definitions, and handle a pen if requested
226    to do so. Ah yes, the xinput-1.2 program reveals Wacom to have numbered
227    the buttons 9, 10, 11, 12 on the left side and 13, 14, 15, 16 on the
228    right. Template:
229
230 Left ExpressKey Pad
231 ------------ 
232 |  |   |   |            Wacom Intuos3 defaults are:
233 |  | 9 | T |
234 |11|---| O |            Key 9  = (left) Shift   = keycode 50
235 |  |10 | U |            Key 10 = (left) Alt     = keycode 64
236 |------| C |            Key 11 = (left) Control = keycode 37
237 |  12  | H |            Key 12 = Space          = keycode 65
238 ------------
239
240 Right ExpressKey Pad
241 ------------ 
242 |   |   |  |            Wacom Intuos3 defaults are:
243 | T |13 |  |
244 | O |---|15|            Key 13 = (left) Shift   = keycode 50
245 | U |14 |  |            Key 14 = (left) Alt     = keycode 64
246 | C |------|            Key 15 = (left) Control = keycode 37
247 | H |  16  |            Key 16 = Space          = keycode 65
248 ------------
249 */
250
251 /* Pad Button Press */
252
253                 if (Event.type == button_press_type) {
254
255                         button = (XDeviceButtonEvent *) &Event;
256
257                         button_index = &p->key_9;
258
259                         for (i = 9; i < button->button; i++) {
260                                 button_index++;
261                                 button_index++;
262                         }
263
264                         if (*button_index == TOGGLE_PEN) {
265                                 if (handle_pen) {
266                                         toggle_pen_mode(display, pen_name);
267                                         if (be_verbose) {
268                                                 fprintf(stderr, "BTN %d = %d\n", button->button, *button_index);
269                                         }
270                                 }
271                         } else {
272                                 if (*button_index) {
273                                         XTestFakeKeyEvent(display, *button_index, True, CurrentTime );
274                                         if (be_verbose) {
275                                                 fprintf(stderr, "BTN %d = %d\n", button->button, *button_index);
276                                         }
277                                 }
278                                 button_index++;
279                                 if (*button_index) {
280                                         XTestFakeKeyEvent(display, *button_index, True, CurrentTime );
281                                         if (be_verbose) {
282                                                 fprintf(stderr, "BTN+ %d = %d\n", button->button, *button_index);
283                                         }
284                                 }
285                         }
286                 }
287
288 /* Pad Button Release */
289
290                 if (Event.type == button_release_type) {
291
292                         button = (XDeviceButtonEvent *) &Event;
293
294                         button_index = &p->key_9;
295
296                         for (i = 9; i < button->button; i++) {
297                                 button_index++;
298                                 button_index++;
299                         }
300
301                         if (*button_index == TOGGLE_PEN) {
302                                 if (be_verbose) {
303                                         fprintf(stderr, "BTN %d = %d\n", button->button, *button_index);
304                                 }
305                         } else {
306                                 button_index++;
307                                 if (*button_index) {
308                                         XTestFakeKeyEvent(display, *button_index, False, CurrentTime );
309                                         if (be_verbose) {
310                                                 fprintf(stderr, "BTN+ %d = %d\n", button->button, *button_index);
311                                         }
312                                 }
313                                 button_index--;
314                                 if (*button_index) {
315                                         XTestFakeKeyEvent(display, *button_index, False, CurrentTime );
316                                         if (be_verbose) {
317                                                 fprintf(stderr, "BTN %d = %d\n", button->button, *button_index);
318                                         }
319                                 }
320                         }
321                 }
322         }
323         exit(EXIT_OK);
324 }
325
326 /* End code */
327