version 0.08
[expresskeys.git] / expresskeys.c
1 /* Version 0.08 3 April 2005
2  *
3  * To compile (example in 2 steps):
4  * gcc -O2 -fomit-frame-pointer -c expresskeys.c
5  * gcc -s -L/usr/X11R6/lib -o expresskeys expresskeys.o -lX11 -lXi -lXext -lXtst
6  *
7  * Run example: expresskeys pad &
8  * Which will push it into the background. It is safe to close the terminal
9  * afterwards. Oh, and X _must_ be running... The name, "pad" here, is
10  * how it's called in xorg.conf (the "Identifier" option).
11  *
12  * Update example 17 March 2005: Myself I've put it in the .xinitrc as
13  * "exec /usr/local/bin/expresskeys pad &" (without quotes) right before
14  * the window manager is started.
15  * 
16  * Key configuration is easy to change in the "user config area" below.
17  * Use the "xev" program to find keycodes or look them up somewhere...
18  * I've set the Wacom Intuos3 defaults on both sides, which is:
19  * Shift, Alt, Control and Space. Touch strips are mildly supported.
20  *
21  * Note 2 April 2005: Sometimes desktops or window managers "steal"
22  * certain keypresses/combinations. If you experience that, look for
23  * a way to change the keybindings of your environment.
24  * 
25  * _Version 0.08 3 April 2005_
26  * 
27  * When I was customizing the keyboard shortcuts within Gimp itself
28  * (I wanted Alt + and Alt - to do Next Brush and Previous Brush) it
29  * became obvious that I couldn't assign these brush steppings to any
30  * touch strip, due to my shortsightedness.
31  * 
32  * Now touch strips can send two keys at a time, just like the pad
33  * buttons: l_touch_up, l_touch_up_plus etc. All of the "_plus" touch
34  * strip definitions are set to 0 (nothing) per default.
35  * 
36  * Being able to use the touch strips for things like this is really
37  * neat. Look in Gimp's File -> Preferences -> Interface -> Configure
38  * Keyboard Shortcuts -> Context for some good touch strip candidates.
39  * 
40  * Bugfix: Would crash if _no_ window had focus (except the root win).
41  *
42  * _Version 0.07 2 April 2005_
43  * 
44  * Multiple configurations to rule them all... Yes, we now send
45  * keypresses intelligently based on several configurations. I've
46  * included a "default" catch all type, one for Gimp, for Blender
47  * and for XTerm. Observe the spelling! It is case sensitive.
48  * 
49  * To create a new definition, just copy a full block and alter the
50  * Name and the keycodes. To find the proper name of a program/window
51  * fire up "xprop". It should be included with your X. xprop without
52  * any arguments expects you to then click on the target window.
53  * What comes out is a flood of information in the terminal window
54  * you used to run xprop from. What we're after is something called
55  * WM_CLASS. And within that, only one string. Let me show you:
56  * 
57  * $ xprop | grep WM_CLASS
58  * WM_CLASS(STRING) = "<unknown>", "Eclipse"
59  * 
60  * It's the last string we would use, the "Eclipse" part. That is,
61  * if we were doing a definition for this program, an IDE ;-)
62  * 
63  * You can see above why I use the last part. Program windows do not
64  * always set their "name" (the first string). But they should
65  * absolutely set the "class" they belong to, which often coincides
66  * with the name.
67  * 
68  * So non-technically, this is how expresskeys works now:
69  * 
70  * 1) Pad button pressed or Touch strips touched.
71  * 2) Examine which window is the current active one (has focus).
72  * 3) Get the "class" name of the window.
73  * 4) Compare that name with an internal list of program names.
74  * 5) If a match is found, use those keydefinitions.
75  * 6) If no match is found, use a "default" set of definitions.
76  * 7) Send the keypress to the specified window.
77  * 
78  * In order to achieve this functionality I had to change the
79  * "user config area" somewhat. I've done my very best to retain
80  * a simple design, and at the same time keep it compact. But
81  * success is in the eye of the beholder... Cut out example:
82  * 
83  *//*   key_9   *//* <-- A visual reminder of which pad button it is. */
84 /*      50,             <-- The actual keycode and a COMMA (don't erase it).
85  * 
86  * Otherwise all the keys and options from past versions are, almost,
87  * the same. End Version Note Rant.
88  * 
89  * _Version 0.06 29 March 2005_
90  * 
91  * Comment 2 April 2005: This is default only in Gimp. Basic defaults
92  * are now Arrow-keys Up/Down/Right/Left. End comment.
93  * 
94  * Touch Strip simple implementation. Default, if turned on, sends plus
95  * (+) and minus (-) key presses based on finger/stylus up/down motion.
96  * This was chosen for Gimp Zoom In/Out functionality. It must be turned
97  * on by setting a value in the "user config area", just as for pen mode
98  * handling. Default is off, don't handle the touch strips.
99  * 
100  * It turns out that with linuxwacom-0.6.7 (beta is out) this program
101  * works better than ever! The blender "confusion" I talked about in
102  * the previous version note has vanished completely. Also blender
103  * zoom, translation and rotation work flawlessly with the pad buttons
104  * and pen middle button (was half-working in linuxwacom-0.6.6). So the
105  * XTestFakeKeyEvent was no bad choice at all. I'm very pleased :-)
106  * 
107  * _Version 0.05 16 March 2005_
108  *
109  * Bugfix. My key scan "case:, if, else, break" flow was somewhat borked.
110  * Ugly function but does the right thing now. There are still issues
111  * with (I believe) the timing of the XTestFakeKeyEvent of the XTest
112  * extension. Using the "u" and "Shift-u" for undo and redo in blender
113  * works, but sometimes blender gets confused. Waiting some seconds and
114  * doing a "slow-push-release" of the key can fix the issue. Ah well,
115  * this simulates keypresses, it's not the real thing... I'll look into
116  * using another extension for the simulation.
117  *
118  * _Version 0.04 15 March 2005_
119  *
120  * Bugfix to handle certain key combinations better. Not perfect though.
121  * Will debug further.
122  *
123  * _Version 0.03 15 March 2005_:
124  * 
125  * Handle a pen from the pad keys (toggle between absolute and relative mode).
126  * See the new "user config area" for details. Observe: Whatever pen mode
127  * you are in when exiting or killing this program, that's the pen mode
128  * you have... So if wrong, fire up the program again and toggle until it's
129  * the right mode. Default is off, don't handle a pen.
130  * 
131  * Clearly marked and cleaned up a "user config area" at the very beginning
132  * of the code.
133  * 
134  * _Version 0.02 14 March 2005_:
135  *
136  * Comment 2 April 2005: These instructions are dated. #define
137  * for the keycodes are not used anymore. End comment.
138  * 
139  * Added the option to specify an extra key for each pad key.
140  * "#define KEY_xx_PLUS yy". By setting yy of KEY_11_PLUS to 57 you'd get
141  * the famous Ctrl-n ;-). I needed this for undo and redo in blender.
142  * 
143  * _Version 0.01 14 March 2005_:
144  *
145  * Original release
146  * 
147  * Have fun,
148  * Mats
149  */
150 /*
151  * CopyLeft 2005 by Mats Johannesson aka Voluspa. One working address
152  * is devel with the ISP bredband which is a net domain.
153  *
154  * Hacked code from xinput-1.2.tar.gz (the test.c, setmode.c and xinput.c)
155  * Most of the pure xinput is left as Frederic Lepied wrote it - I'm no coder!
156  */
157 /*
158  * Copyright 1996 by Frederic Lepied, France. <Frederic.Lepied@sugix.frmug.org>
159  *                                                                            
160  * Permission to use, copy, modify, distribute, and sell this software and its
161  * documentation for any purpose is  hereby granted without fee, provided that
162  * the  above copyright   notice appear  in   all  copies and  that both  that
163  * copyright  notice   and   this  permission   notice  appear  in  supporting
164  * documentation, and that   the  name of  Frederic   Lepied not  be  used  in
165  * advertising or publicity pertaining to distribution of the software without
166  * specific,  written      prior  permission.     Frederic  Lepied   makes  no
167  * representations about the suitability of this software for any purpose.  It
168  * is provided "as is" without express or implied warranty.                   
169  *                                                                            
170  * FREDERIC  LEPIED DISCLAIMS ALL   WARRANTIES WITH REGARD  TO  THIS SOFTWARE,
171  * INCLUDING ALL IMPLIED   WARRANTIES OF MERCHANTABILITY  AND   FITNESS, IN NO
172  * EVENT  SHALL FREDERIC  LEPIED BE   LIABLE   FOR ANY  SPECIAL, INDIRECT   OR
173  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
174  * DATA  OR PROFITS, WHETHER  IN  AN ACTION OF  CONTRACT,  NEGLIGENCE OR OTHER
175  * TORTIOUS  ACTION, ARISING    OUT OF OR   IN  CONNECTION  WITH THE USE    OR
176  * PERFORMANCE OF THIS SOFTWARE.
177  *
178  */
179
180 /* ++++++++++ Begin user config area ++++++++++ */
181
182 #define HANDLE_PEN 0    /* Main switch: 1 = yes handle a pen, 0 = no please */
183 #define PEN_NAME "stylus"       /* Identifier name as configured in xorg.conf */
184 #define PEN_MODE "Absolute"     /* The mode we should expect the pen to be in */
185                         /* when starting this program. Default usually */
186                         /* is Absolute. The "mousy" feeling is Relative */
187
188 /* Now, on to the next area. Please walk this way madam!                */
189 /*----------------------------------------------.                       */
190 struct program {                /*              |                       */
191         char *class_name;       /*              |                       */
192         int handle_touch;       /*              |                       */
193         int l_touch_up;         /*              |                       */
194         int l_touch_up_plus;    /*              |                       */
195         int l_touch_down;       /*              |                       */
196         int l_touch_down_plus;  /*              |                       */
197         int r_touch_up;         /*              |                       */
198         int r_touch_up_plus;    /*              |                       */
199         int r_touch_down;       /*              |                       */
200         int r_touch_down_plus;  /*              |                       */
201         int key_9;              /*              |                       */
202         int key_9_plus;         /*              |                       */
203         int key_10;             /*              |                       */
204         int key_10_plus;        /*              |                       */
205         int key_11;             /*      Nothing to see here             */
206         int key_11_plus;        /*      madam... Please move            */
207         int key_12;             /*      along.                          */
208         int key_12_plus;        /*              |                       */
209         int key_13;             /*              |                       */
210         int key_13_plus;        /*              |                       */
211         int key_14;             /*              |                       */
212         int key_14_plus;        /*              |                       */
213         int key_15;             /*              |                       */
214         int key_15_plus;        /*              |                       */
215         int key_16;             /*              |                       */
216         int key_16_plus;        /*              |                       */
217 } prog_list[] = {               /*              |                       */
218                                 /*              |                       */
219 /*-------------------------------.              V                       */
220 /*                                      Go further down, past
221  *                                      these comments for the
222  *                                      real configuration area.
223  */
224 /* Left ExpressKey Pad
225 ------------ 
226 |  |   |   |            Wacom Intuos3 defaults are:
227 |  | 9 | T |
228 |11|---| O |            Key 9  = (left) Shift   = keycode 50
229 |  |10 | U |            Key 10 = (left) Alt     = keycode 64
230 |------| C |            Key 11 = (left) Control = keycode 37
231 |  12  | H |            Key 12 = Space          = keycode 65
232 ------------
233 */
234 /* Right ExpressKey Pad
235 ------------ 
236 |   |   |  |            Wacom Intuos3 defaults are:
237 | T |13 |  |
238 | O |---|15|            Key 13 = (left) Shift   = keycode 50
239 | U |14 |  |            Key 14 = (left) Alt     = keycode 64
240 | C |------|            Key 15 = (left) Control = keycode 37
241 | H |  16  |            Key 16 = Space          = keycode 65
242 ------------
243 */
244
245 /* The top configuration (named "default") will be used with
246  * all programs and their windows that are not specified in a
247  * separate configuration below this one. Default keycodes are
248  * the now famous Wacom Intuos3 ones. I've also set totally
249  * non-destructive touch strip keys (only used if handle_touch
250  * is altered to a "1" - without quotes) which are: Arrow-keys
251  * Up/Down on the left strip and Arrow-keys Right/Left on the
252  * right strip. Change direction of the movement by switching
253  * the _up and _down values.
254  * 
255  * If you want a key to do pen mode changes, use the value 999
256  * under the corresponding keylabel. To be able to switch mode
257  * anywhere, each configuration must contain one 999 definition.
258  * And, of course, the main HANDLE_PEN definition above must
259  * first be set to "1" - without quotes.
260  * 
261  * Please don't alter or remove the commas (,) after the keycodes.
262  * They _must_ be there just as written.
263  */
264 /*      Name    handle_touch */
265 {"default",     0,
266 /*              l_touch_up      l_touch_up_plus l_touch_down    l_touch_down_plus */
267                 98,             0,              104,            0,
268 /*              r_touch_up      r_touch_up_plus r_touch_down    r_touch_down_plus */
269                 102,            0,              100,            0,
270 /*              key_9           key_9_plus      key_10          key_10_plus */
271                 50,             0,              64,             0,
272 /*              key_11          key_11_plus     key_12          key_12_plus */
273                 37,             0,              65,             0,
274 /*              key_13          key_13_plus     key_14          key_14_plus */
275                 50,             0,              64,             0,
276 /*              key_15          key_15_plus     key_16          key_16_plus */
277                 37,             0,              65,             0       },
278
279 /*
280  * Gimp has the touch strips turned on by default. The keycodes are:
281  * 20 = "+" = Gimp Zoom In. Left/Right touch strip up motion
282  * 61 = "-" = Gimp Zoom Out. Left/Right touch strip down motion
283  * Change direction of the movement by switching _up and _down values.
284  */
285 /*      Name    handle_touch */
286 {"Gimp",        1,
287 /*              l_touch_up      l_touch_up_plus l_touch_down    l_touch_down_plus */
288                 20,             0,              61,             0,
289 /*              r_touch_up      r_touch_up_plus r_touch_down    r_touch_down_plus */
290                 20,             0,              61,             0,
291 /*              key_9           key_9_plus      key_10          key_10_plus */
292                 50,             0,              64,             0,
293 /*              key_11          key_11_plus     key_12          key_12_plus */
294                 37,             0,              65,             0,
295 /*              key_13          key_13_plus     key_14          key_14_plus */
296                 50,             0,              64,             0,
297 /*              key_15          key_15_plus     key_16          key_16_plus */
298                 37,             0,              65,             0       },
299
300 /* This is my private definition for the 3D program blender...
301  */
302 /*      Name    handle_touch */
303 {"Blender",     1,
304 /*              l_touch_up      l_touch_up_plus l_touch_down    l_touch_down_plus */
305                 102,            0,              100,            0,
306 /*              r_touch_up      r_touch_up_plus r_touch_down    r_touch_down_plus */
307                 98,             0,              104,            0,
308 /*              key_9           key_9_plus      key_10          key_10_plus */
309                 37,             0,              9,              0,
310 /*              key_11          key_11_plus     key_12          key_12_plus */
311                 50,             0,              23,             0,
312 /*              key_13          key_13_plus     key_14          key_14_plus */
313                 50,             30,             30,             0,
314 /*              key_15          key_15_plus     key_16          key_16_plus */
315                 999,            0,              65,             0       },
316
317 /* I feel that an xterm is too important a window to have _any_
318  * interference from the pad. But observe that I want to be able
319  * to switch pen mode even with such a window in focus.
320  */
321 /*      Name    handle_touch */
322 {"XTerm",       0,
323 /*              l_touch_up      l_touch_up_plus l_touch_down    l_touch_down_plus */
324                 0,              0,              0,              0,
325 /*              r_touch_up      r_touch_up_plus r_touch_down    r_touch_down_plus */
326                 0,              0,              0,              0,
327 /*              key_9           key_9_plus      key_10          key_10_plus */
328                 0,              0,              0,              0,
329 /*              key_11          key_11_plus     key_12          key_12_plus */
330                 0,              0,              0,              0,
331 /*              key_13          key_13_plus     key_14          key_14_plus */
332                 0,              0,              0,              0,
333 /*              key_15          key_15_plus     key_16          key_16_plus */
334                 999,            0,              0,              0       },
335
336 /* And that's how it's done. Just copy a section and tweak the
337  * settings for a new program. Your machine speed and memory
338  * sets the limit ;-)
339  */
340 /* ++++++++++ End user config area ++++++++++ */
341
342 };
343 #define NUM_LIST (sizeof prog_list / sizeof prog_list[0])
344
345 #include <X11/Xlib.h>
346 #include <X11/Xutil.h>
347 #include <X11/extensions/XInput.h>
348 #include <X11/extensions/XTest.h>
349 #include <stdio.h>
350 #include <stdlib.h>
351 #include <ctype.h>
352 #include <string.h>
353
354 #define EXIT_OK 1
355 #define EXIT_KO 0
356 #define INVALID_EVENT_TYPE -1
357 #define TOGGLE_PEN 999
358
359 Bool check_xinput (Display *display);
360 int find_device_info(Display *display, char *name, Bool only_extended);
361 int register_events(Display     *display, XDeviceInfo *info, char *dev_name);
362 int use_events(Display *display);
363 int toggle_pen_mode(Display *display, char *name);
364
365 int pen_mode = 1;
366 int elder_rotation = 4097;
367 int old_rotation = 4097;
368 int elder_throttle = 4097;
369 int old_throttle = 4097;
370
371 int main (int argc, char *argv[])
372 {
373
374                 if (PEN_MODE == "Absolute") {
375                 pen_mode = Absolute;
376                 } else {
377                 pen_mode = Relative;
378                 }
379
380         Display *display = XOpenDisplay(NULL);
381
382         if (display == NULL) {
383                 fprintf(stderr, "Can not connect to X-Server\n");
384                 return EXIT_KO;
385         }
386
387         int event_base, error_base;
388         int major_version, minor_version;
389         if (!XTestQueryExtension (display, &event_base, &error_base,
390         &major_version, &minor_version)) {
391                 fprintf (stderr, "XTest extension not supported on server\n");
392                 XCloseDisplay(display);
393                 return EXIT_KO;
394         }
395
396         if (!check_xinput(display)) {
397                 fprintf(stderr, "%s extension not present\n", INAME);
398                 XCloseDisplay(display);
399                 return EXIT_KO;
400         }
401
402         if (argc < 2) {
403                 fprintf(stderr, "Usage: expresskeys <device-name>\n");
404                 fprintf(stderr, "Example: expresskeys pad &\n");
405                 XCloseDisplay(display);
406                 return EXIT_KO;
407         }
408
409         XDeviceInfo     *info;
410         int             idx = 1;
411
412         info = find_device_info(display, argv[idx], True);
413
414                 if (!info) {
415                 fprintf(stderr, "Unable to find device %s\n", argv[idx]);
416                 XCloseDisplay(display);         
417                 return EXIT_KO;
418         }
419
420         if (register_events(display, info, argv[idx])) {
421                 use_events(display);
422         } else {
423                 fprintf(stderr, "No event registered...\n");
424                 XCloseDisplay(display);
425                 return EXIT_KO;
426                 }
427
428         XCloseDisplay(display);
429         return EXIT_OK;
430 }
431
432 Bool check_xinput (Display *display)
433 {
434         XExtensionVersion *version;
435         Bool present;
436         
437         version = XGetExtensionVersion (display, INAME);
438         
439         if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
440                 present = version->present;
441                 XFree(version);
442                 return present;
443         } else {
444                 return False;
445         }
446 }       
447
448 int find_device_info(Display *display, char *name, Bool only_extended)
449 {
450         XDeviceInfo     *devices; 
451         int             loop;
452         int             num_devices;
453         int             len = strlen(name);
454         Bool            is_id = True;
455         XID             id = 0;
456     
457         for(loop=0; loop<len; loop++) {
458         if (!isdigit(name[loop])) {
459                 is_id = False;
460                 break;
461         }
462         }
463
464         if (is_id) {
465         id = atoi(name);
466         }
467     
468         devices = XListInputDevices(display, &num_devices);
469
470         for(loop=0; loop<num_devices; loop++) {
471         if ((!only_extended || (devices[loop].use == IsXExtensionDevice)) &&
472                 ((!is_id && strcmp(devices[loop].name, name) == 0) ||
473                 (is_id && devices[loop].id == id))) {
474                 return &devices[loop];
475                 }
476         }
477         return 0;
478 }
479
480 static int motion_type = INVALID_EVENT_TYPE;
481 static int button_press_type = INVALID_EVENT_TYPE;
482 static int button_release_type = INVALID_EVENT_TYPE;
483 int register_events(Display     *display, XDeviceInfo *info, char *dev_name)
484 {
485         int number = 0;
486         XEventClass event_list[3];
487         int i;
488         XDevice *device;
489         Window root_win;
490         unsigned long screen;
491         XInputClassInfo *ip;
492
493         screen = DefaultScreen(display);
494         root_win = RootWindow(display, screen);
495
496         device = XOpenDevice(display, info->id);
497
498         if (!device) {
499         fprintf(stderr, "Unable to open device %s\n", dev_name);
500         return 0;
501         }
502
503         if (device->num_classes > 0) {
504         for (ip = device->classes, i=0; i<info->num_classes; ip++, i++) {
505                 switch (ip->input_class) {
506
507                 case ButtonClass:
508                 DeviceButtonPress(device, button_press_type, event_list[number]); number++;
509                 DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
510                 break;
511
512                 case ValuatorClass:
513                 DeviceMotionNotify(device, motion_type, event_list[number]); number++;
514                 break;
515
516                 default:
517                 break;
518             }
519                 }
520         if (XSelectExtensionEvent(display, root_win, event_list, number)) {
521                 fprintf(stderr, "Error selecting extended events\n");
522                 return 0;               
523                 }
524         }
525         return number;  
526 }
527
528 int use_events(Display *display)
529 {
530         
531         XEvent Event;
532         while(1) {
533                 XNextEvent(display, &Event);
534
535                 XClassHint *class_hint;
536                 class_hint = XAllocClassHint();
537
538                 Window focus_window = None;
539                 int focus_state;
540
541                 Window root, parent;
542                 Window *children;
543                 unsigned int num_children;
544
545                 struct program *p;
546                 int in_list = 0;
547
548                 XGetInputFocus(display, &focus_window, &focus_state);
549                 XQueryTree(display, focus_window, &root, &parent, &children, &num_children);
550                 XGetClassHint(display, focus_window, class_hint);
551
552                 if ((!class_hint->res_class) && (focus_window != root)){
553                         XFree(class_hint->res_class);
554                         XFree(class_hint->res_name);
555                         XGetClassHint(display, parent, class_hint);
556                 }
557
558                 if (focus_window == root){
559                         p = prog_list;
560                 }
561                 else {
562                         for (p = prog_list; p < prog_list + NUM_LIST; p++)
563                                 if (strcmp (class_hint->res_class, p->class_name) == 0){
564                                         in_list = 1;
565                                         break;
566                                 }
567                         }
568                 
569                 XFree(class_hint->res_class);
570                 XFree(class_hint->res_name);
571                 if (children) XFree((char *)children);
572
573                 if (!in_list){
574                         p = prog_list;
575                 }
576
577         if (Event.type == motion_type) {
578
579                 if (p->handle_touch){
580                         int rotation;
581                         int throttle;
582         
583                 XDeviceMotionEvent *motion = (XDeviceMotionEvent *) &Event;
584
585                         rotation = motion->axis_data[3];
586                         throttle = motion->axis_data[4];
587
588                         if (rotation > 1){
589                                 if ((rotation < old_rotation) && (old_rotation <= elder_rotation)){
590                                         if (p->l_touch_up){
591                                                 XTestFakeKeyEvent(display, p->l_touch_up, True, CurrentTime);
592                                                 if (p->l_touch_up_plus){
593                                                         XTestFakeKeyEvent(display, p->l_touch_up_plus, True, CurrentTime);
594                                                         XTestFakeKeyEvent(display, p->l_touch_up_plus, False, CurrentTime);
595                                                 }
596                                                 XTestFakeKeyEvent(display, p->l_touch_up, False, CurrentTime);
597                                         }
598                                 }
599                                 else if ((rotation > old_rotation) && (old_rotation >= elder_rotation)){
600                                         if (p->l_touch_down){
601                                                 XTestFakeKeyEvent(display, p->l_touch_down, True, CurrentTime);
602                                                 if (p->l_touch_down_plus){
603                                                         XTestFakeKeyEvent(display, p->l_touch_down_plus, True, CurrentTime);
604                                                         XTestFakeKeyEvent(display, p->l_touch_down_plus, False, CurrentTime);
605                                                 }
606                                                 XTestFakeKeyEvent(display, p->l_touch_down, False, CurrentTime);
607                                         }
608                                 }
609                         elder_rotation = old_rotation;
610                         old_rotation = rotation;
611                         }
612
613                         if (throttle > 1){
614                                 if ((throttle < old_throttle) && (old_throttle <= elder_throttle)){
615                                         if (p->r_touch_up){
616                                                 XTestFakeKeyEvent(display, p->r_touch_up, True, CurrentTime);
617                                                 if (p->r_touch_up_plus){
618                                                         XTestFakeKeyEvent(display, p->r_touch_up_plus, True, CurrentTime);
619                                                         XTestFakeKeyEvent(display, p->r_touch_up_plus, False, CurrentTime);
620                                                 }
621                                                 XTestFakeKeyEvent(display, p->r_touch_up, False, CurrentTime);
622                                         }
623                                 }
624                                 else if ((throttle > old_throttle) && (old_throttle >= elder_throttle)){
625                                         if (p->r_touch_down){
626                                                 XTestFakeKeyEvent(display, p->r_touch_down, True, CurrentTime);
627                                                 if (p->r_touch_down_plus){
628                                                         XTestFakeKeyEvent(display, p->r_touch_down_plus, True, CurrentTime);
629                                                         XTestFakeKeyEvent(display, p->r_touch_down_plus, False, CurrentTime);
630                                                 }
631                                                 XTestFakeKeyEvent(display, p->r_touch_down, False, CurrentTime);
632                                         }
633                                 }
634                         elder_throttle = old_throttle;
635                         old_throttle = throttle;
636                         }
637                 }
638         }
639
640         if (Event.type == button_press_type) {
641
642                 XDeviceButtonEvent *button = (XDeviceButtonEvent *) &Event;
643
644                 switch (button->button) {
645                         case 9:
646                 if (p->key_9 == TOGGLE_PEN)
647                         if (HANDLE_PEN)
648                                 toggle_pen_mode(display, PEN_NAME);
649                         else
650                                 break;
651                 else
652                 if (p->key_9)
653 XTestFakeKeyEvent(display, p->key_9, True, CurrentTime );
654                 if (p->key_9_plus)
655 XTestFakeKeyEvent(display, p->key_9_plus, True, CurrentTime );
656                 else
657                         break;
658                         break;
659                         case 10:
660                 if (p->key_10 == TOGGLE_PEN)
661                         if (HANDLE_PEN)
662                                 toggle_pen_mode(display, PEN_NAME);
663                         else
664                                 break;
665                 else
666                 if (p->key_10)
667 XTestFakeKeyEvent(display, p->key_10, True, CurrentTime );
668                 if (p->key_10_plus)
669 XTestFakeKeyEvent(display, p->key_10_plus, True, CurrentTime );
670                 else
671                         break;
672                         break;
673                         case 11:
674                 if (p->key_11 == TOGGLE_PEN)
675                         if (HANDLE_PEN)
676                                 toggle_pen_mode(display, PEN_NAME);
677                         else
678                                 break;
679                 else
680                 if (p->key_11)
681 XTestFakeKeyEvent(display, p->key_11, True, CurrentTime );
682                 if (p->key_11_plus)
683 XTestFakeKeyEvent(display, p->key_11_plus, True, CurrentTime );
684                 else
685                         break;
686                         break;
687                         case 12:
688                 if (p->key_12 == TOGGLE_PEN)
689                         if (HANDLE_PEN)
690                                 toggle_pen_mode(display, PEN_NAME);
691                         else
692                                 break;
693                 else
694                 if (p->key_12)
695 XTestFakeKeyEvent(display, p->key_12, True, CurrentTime );
696                 if (p->key_12_plus)
697 XTestFakeKeyEvent(display, p->key_12_plus, True, CurrentTime );
698                 else
699                         break;
700                         break;
701                         case 13:
702                 if (p->key_13 == TOGGLE_PEN)
703                         if (HANDLE_PEN)
704                                 toggle_pen_mode(display, PEN_NAME);
705                         else
706                                 break;
707                 else
708                 if (p->key_13)
709 XTestFakeKeyEvent(display, p->key_13, True, CurrentTime );
710                 if (p->key_13_plus)
711 XTestFakeKeyEvent(display, p->key_13_plus, True, CurrentTime );
712                 else
713                         break;
714                         break;
715                         case 14:
716                 if (p->key_14 == TOGGLE_PEN)
717                         if (HANDLE_PEN)
718                                 toggle_pen_mode(display, PEN_NAME);
719                         else
720                                 break;
721                 else
722                 if (p->key_14)
723 XTestFakeKeyEvent(display, p->key_14, True, CurrentTime );
724                 if (p->key_14_plus)
725 XTestFakeKeyEvent(display, p->key_14_plus, True, CurrentTime );
726                 else
727                         break;
728                         break;
729                         case 15:
730                 if (p->key_15 == TOGGLE_PEN)
731                         if (HANDLE_PEN)
732                                 toggle_pen_mode(display, PEN_NAME);
733                         else
734                                 break;
735                 else
736                 if (p->key_15)
737 XTestFakeKeyEvent(display, p->key_15, True, CurrentTime );
738                 if (p->key_15_plus)
739 XTestFakeKeyEvent(display, p->key_15_plus, True, CurrentTime );
740                 else
741                         break;
742                         break;
743                         case 16:
744                 if (p->key_16 == TOGGLE_PEN)
745                         if (HANDLE_PEN)
746                                 toggle_pen_mode(display, PEN_NAME);
747                         else
748                                 break;
749                 else
750                 if (p->key_16)
751 XTestFakeKeyEvent(display, p->key_16, True, CurrentTime );
752                 if (p->key_16_plus)
753 XTestFakeKeyEvent(display, p->key_16_plus, True, CurrentTime );
754                 else
755                         break;
756                         break;                  
757                         default:
758                         break;
759                 }
760         }
761
762         if (Event.type == button_release_type) {
763                 XDeviceButtonEvent *button = (XDeviceButtonEvent *) &Event;
764
765         switch (button->button) {
766                         case 9:
767                 if (p->key_9 == TOGGLE_PEN)
768                         break;
769                 else
770                 if (p->key_9_plus)
771 XTestFakeKeyEvent(display, p->key_9_plus, False, CurrentTime );
772                 if (p->key_9)
773 XTestFakeKeyEvent(display, p->key_9, False, CurrentTime );
774                 else
775                         break;
776                         break;
777                         case 10:
778                 if (p->key_10 == TOGGLE_PEN)            
779                         break;
780                 else
781                 if (p->key_10_plus)
782 XTestFakeKeyEvent(display, p->key_10_plus, False, CurrentTime );
783                 if (p->key_10)
784 XTestFakeKeyEvent(display, p->key_10, False, CurrentTime );
785                 else
786                         break;
787                         break;
788                         case 11:
789                 if (p->key_11 == TOGGLE_PEN)
790                         break;
791                 else
792                 if (p->key_11_plus)
793 XTestFakeKeyEvent(display, p->key_11_plus, False, CurrentTime );
794                 if (p->key_11)
795 XTestFakeKeyEvent(display, p->key_11, False, CurrentTime );
796                 else
797                         break;
798                         break;
799                         case 12:
800                 if (p->key_12 == TOGGLE_PEN)
801                         break;
802                 else
803                 if (p->key_12_plus)
804 XTestFakeKeyEvent(display, p->key_12_plus, False, CurrentTime );
805                 if (p->key_12)
806 XTestFakeKeyEvent(display, p->key_12, False, CurrentTime );
807                 else
808                         break;
809                         break;
810                         case 13:
811                 if (p->key_13 == TOGGLE_PEN)
812                         break;
813                 else
814                 if (p->key_13_plus)             
815 XTestFakeKeyEvent(display, p->key_13_plus, False, CurrentTime );
816                 if (p->key_13)
817 XTestFakeKeyEvent(display, p->key_13, False, CurrentTime );
818                 else
819                         break;
820                         break;
821                         case 14:
822                 if (p->key_14 == TOGGLE_PEN)
823                         break;
824                 else
825                 if (p->key_14_plus)
826 XTestFakeKeyEvent(display, p->key_14_plus, False, CurrentTime );
827                 if (p->key_14)
828 XTestFakeKeyEvent(display, p->key_14, False, CurrentTime );
829                 else
830                         break;
831                         break;
832                         case 15:
833                 if (p->key_15 == TOGGLE_PEN)
834                         break;
835                 else
836                 if (p->key_15_plus)
837 XTestFakeKeyEvent(display, p->key_15_plus, False, CurrentTime );
838                 if (p->key_15)
839 XTestFakeKeyEvent(display, p->key_15, False, CurrentTime );
840                 else
841                         break;
842                         break;
843                         case 16:
844                 if (p->key_16 == TOGGLE_PEN)
845                         break;
846                 else
847                 if (p->key_16_plus)
848 XTestFakeKeyEvent(display, p->key_16_plus, False, CurrentTime );
849                 if (p->key_16)
850 XTestFakeKeyEvent(display, p->key_16, False, CurrentTime );
851                 else
852                         break;
853                         break;
854                         default:
855                         break;
856                         }
857                 }
858         }
859 }
860
861 int toggle_pen_mode(Display *display, char *name)
862 {
863
864         XDeviceInfo     *info;
865         XDevice         *device;
866
867         info = find_device_info(display, PEN_NAME, True);
868
869         if (!info) {
870                 fprintf(stderr, "unable to find device %s\n", PEN_NAME);
871                 return 0;
872         }
873
874         if (pen_mode == Absolute) {
875         pen_mode = Relative;
876         } else {
877         pen_mode = Absolute;
878         }
879
880         device = XOpenDevice(display, info->id);
881
882         if (device) {
883         XSetDeviceMode(display, device, pen_mode);
884         return 0;
885         } else {
886         fprintf(stderr, "Unable to open device %s\n", PEN_NAME);
887         return 0;
888         }
889 }
890
891 /* End code */
892