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