Added lirc.
[irreco.git] / lirc-0.8.4a / contrib / sendxevent.c
blob8cfb564db655a4df751e7f0b142bffd697a537c9
1 /*
2 sendxevent.c
4 02/04/2002: This is a quick hack to make a version of this program (irxevent)
5 which takes its input from the commandline, rather than from a
6 combination of an lirc config file, and an lirc ir code.
8 NOTE: it also includes the more general purpose RootWindow support, which
9 is a nice 3 line addition to the original program as well, allowing
10 the window id field to understand RootWindow as well as CurrentWindow
12 I compile with 'gcc -L/usr/X11R6/lib -lX11 -o sendxevent sendxevent.c'
14 Doug McClendon - <filteredperception@sbcglobal.net>
17 #define VERSION "hack"
19 /* $Id: sendxevent.c,v 1.1 2002/03/25 17:20:45 lirc Exp $ */
21 /****************************************************************************
22 ** irxevent.c **************************************************************
23 ****************************************************************************
25 * irxevent - infra-red xevent sender
27 * Heinrich Langos <heinrich@null.net>
28 * small modifications by Christoph Bartelmus <lirc@bartelmus.de>
30 * irxevent is based on irexec (Copyright (C) 1998 Trent Piepho)
31 * and irx.c (no copyright notice found)
33 * =======
34 * HISTORY
35 * =======
37 * 0.1
38 * -Initial Release
40 * 0.2
41 * -no more XWarpPointer... sending Buttonclicks to off-screen
42 * applications works becaus i also fake the EnterNotify and LeaveNotify
43 * -support for keysymbols rather than characters... so you can use
44 * Up or Insert or Control_L ... maybe you could play xquake than :*)
46 * 0.3
47 * -bugfix for looking for subwindows of non existing windows
48 * -finaly a README file
50 * 0.3a (done by Christoph Bartelmus)
51 * -read from a shared .lircrc file
52 * -changes to comments
53 * (chris, was that all you changed?)
55 * 0.4
56 * -fake_timestamp() to solve gqmpeg problems
57 * -Shift Control and other mod-keys may work. (can't check it right now)
58 * try ctrl-c or shift-Page_up or whatever ...
59 * modifiers: shift, caps, ctrl, alt, meta, numlock, mod3, mod4, scrlock
60 * -size of 'char *keyname' changed from 64 to 128 to allow all mod-keys.
61 * -updated irxevent.README
63 * 0.4.1
64 * -started to make smaller version steps :-)
65 * -Use "CurrentWindow" as window name to send events to the window
66 * that -you guessed it- currently has the focus.
68 * 0.4.2
69 * -fixed a stupid string bug in key sending.
70 * -updated irxevent.README to be up to date with the .lircrc format.
72 * 0.4.3
73 * -changed DEBUG functions to actually produce some output :)
75 * 0.5.0
76 * -fixed finding subwindows recursively
77 * -added xy_Key (though xterm and xemacs still don't like me)
78 * -added compilation patch from Ben Hochstedler
79 * <benh@eeyore.moneng.mei.com> for compiling on systems
80 * without strsep() (like some solaris)
83 * see http://www.wh9.tu-dresden.de/~heinrich/lirc/irxevent/irxevent.keys
84 * for a the key names. (this one is for you Pablo :-) )
86 * for more information see the irxevent.README file
90 #ifdef HAVE_CONFIG_H
91 # include <config.h>
92 #endif
94 #include <errno.h>
95 #include <unistd.h>
96 #include <getopt.h>
97 #include <stdarg.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <sys/socket.h>
102 #include <sys/un.h>
103 #include <sys/stat.h>
104 #include <sys/types.h>
106 #include <X11/Xlib.h>
107 #include <X11/Xutil.h>
108 #include <sys/time.h>
109 #include <unistd.h>
111 /* #define DEBUG */
112 #ifdef DEBUG
113 void debugprintf(char *format_str, ...)
115 va_list ap;
116 va_start(ap,format_str);
117 vfprintf(stderr,format_str,ap);
118 va_end(ap);
120 #else
121 void debugprintf(char *format_str, ...)
124 #endif
127 struct keymodlist_t {
128 char *name;
129 Mask mask;
131 static struct keymodlist_t keymodlist[]=
133 {"SHIFT", ShiftMask},
134 {"CAPS", LockMask},
135 {"CTRL", ControlMask},
136 {"ALT", Mod1Mask},{"META", Mod1Mask},
137 {"NUMLOCK", Mod2Mask},
138 {"MOD3", Mod3Mask}, /* I don't have a clue what key maps to this. */
139 {"MOD4", Mod4Mask}, /* I don't have a clue what key maps to this. */
140 {"SCRLOCK", Mod5Mask},
141 {NULL,0},
144 const char *key_delimiter ="-";
145 const char *active_window_name ="CurrentWindow";
146 const char *root_window_name ="RootWindow";
149 char *progname;
150 Display *dpy;
151 Window root;
152 XEvent xev;
153 Window w,subw;
155 Time fake_timestamp()
156 /*seems that xfree86 computes the timestamps like this */
157 /*strange but it relies on the *1000-32bit-wrap-around */
158 /*if anybody knows exactly how to do it, please contact me */
160 int tint;
161 struct timeval tv;
162 struct timezone tz; /* is not used since ages */
163 gettimeofday(&tv,&tz);
164 tint=(int)tv.tv_sec*1000;
165 tint=tint/1000*1000;
166 tint=tint+tv.tv_usec/1000;
167 return (Time)tint;
170 Window find_window(Window top,char *name)
172 char *wname,*iname;
173 XClassHint xch;
174 Window *children,foo;
175 int revert_to_return;
176 unsigned int nc;
177 if (!strcmp(active_window_name,name)){
178 XGetInputFocus(dpy, &foo, &revert_to_return);
179 return(foo);
180 } else if(!strcmp(root_window_name,name)){
181 return(root);
183 /* First the base case */
184 if (XFetchName(dpy,top,&wname)){
185 if (!strncmp(wname,name,strlen(name))) {
186 XFree(wname);
187 debugprintf("found it by wname %x \n",top);
188 return(top); /* found it! */
190 XFree(wname);
193 if(XGetIconName(dpy,top,&iname)){
194 if (!strncmp(iname,name,strlen(name))) {
195 XFree(iname);
196 debugprintf("found it by iname %x \n",top);
197 return(top); /* found it! */
199 XFree(iname);
202 if(XGetClassHint(dpy,top,&xch)) {
203 if(!strcmp(xch.res_class,name)) {
204 XFree(xch.res_name); XFree(xch.res_class);
205 debugprintf("res_class '%s' res_name '%s' %x \n", xch.res_class,xch.res_name,top);
206 return(top); /* found it! */
208 if(!strcmp(xch.res_name,name)) {
209 XFree(xch.res_name); XFree(xch.res_class);
210 debugprintf("res_class '%s' res_name '%s' %x \n", xch.res_class,xch.res_name,top);
211 return(top); /* found it! */
213 XFree(xch.res_name); XFree(xch.res_class);
216 if(!XQueryTree(dpy,top,&foo,&foo,&children,&nc) || children==NULL) {
217 return(0); /* no more windows here */
220 /* check all the sub windows */
221 for(;nc>0;nc--) {
222 top = find_window(children[nc-1],name);
223 if(top) break; /* we found it somewhere */
225 if(children!=NULL) XFree(children);
226 return(top);
229 Window find_sub_sub_window(Window top,int *x, int *y)
231 Window base;
232 Window *children,foo,target=0;
233 unsigned int nc,
234 rel_x,rel_y,width,height,border,depth,
235 new_x=1,new_y=1,
236 targetsize=1000000;
238 base=top;
239 if (!base) {return base;};
240 if(!XQueryTree(dpy,base,&foo,&foo,&children,&nc) || children==NULL) {
241 return(base); /* no more windows here */
243 debugprintf("found subwindows %d\n",nc);
245 /* check if we hit a sub window and find the smallest one */
246 for(;nc>0;nc--) {
247 if(XGetGeometry(dpy, children[nc-1], &foo, &rel_x, &rel_y,
248 &width, &height, &border, &depth)){
249 if ((rel_x<=*x)&&(*x<=rel_x+width)&&(rel_y<=*y)&&(*y<=rel_y+height)){
250 debugprintf("found a subwindow %x +%d +%d %d x %d \n",children[nc-1], rel_x,rel_y,width,height);
251 if ((width*height)<targetsize){
252 target=children[nc-1];
253 targetsize=width*height;
254 new_x=*x-rel_x;
255 new_y=*y-rel_y;
256 /*bull's eye ...*/
257 target=find_sub_sub_window(target,&new_x,&new_y);
262 if(children!=NULL) XFree(children);
263 if (target){
264 *x=new_x;
265 *y=new_y;
266 return target;
267 }else
268 return base;
273 Window find_sub_window(Window top,char *name,int *x, int *y)
275 Window base;
276 Window *children,foo,target=0;
277 unsigned int nc,
278 rel_x,rel_y,width,height,border,depth,
279 new_x=1,new_y=1,
280 targetsize=1000000;
282 base=find_window(top, name);
283 if (!base) {return base;};
284 if(!XQueryTree(dpy,base,&foo,&foo,&children,&nc) || children==NULL) {
285 return(base); /* no more windows here */
287 debugprintf("found subwindows %d\n",nc);
289 /* check if we hit a sub window and find the smallest one */
290 for(;nc>0;nc--) {
291 if(XGetGeometry(dpy, children[nc-1], &foo, &rel_x, &rel_y,
292 &width, &height, &border, &depth)){
293 if ((rel_x<=*x)&&(*x<=rel_x+width)&&(rel_y<=*y)&&(*y<=rel_y+height)){
294 debugprintf("found a subwindow %x +%d +%d %d x %d \n",children[nc-1], rel_x,rel_y,width,height);
295 if ((width*height)<targetsize){
296 target=children[nc-1];
297 targetsize=width*height;
298 new_x=*x-rel_x;
299 new_y=*y-rel_y;
300 /*bull's eye ...*/
301 target=find_sub_sub_window(target,&new_x,&new_y);
306 if(children!=NULL) XFree(children);
307 if (target){
308 *x=new_x;
309 *y=new_y;
310 return target;
311 }else
312 return base;
316 void make_button(int button,int x,int y,XButtonEvent *xev)
318 xev->type = ButtonPress;
319 xev->display=dpy;
320 xev->root=root;
321 xev->subwindow=None;
322 xev->time=fake_timestamp();
323 xev->x=x;xev->y=y;
324 xev->x_root=1; xev->y_root=1;
325 xev->state=0;
326 xev->button=button;
327 xev->same_screen=True;
329 return;
332 void make_key(char *keyname,int x, int y,XKeyEvent *xev)
334 char *part, *part2;
335 struct keymodlist_t *kmlptr;
336 char tmpkeyname[128];
337 strncpy(tmpkeyname,keyname,128);
338 part2=malloc(128);
340 xev->type = KeyPress;
341 xev->display=dpy;
342 xev->root=root;
343 xev->subwindow = None;
344 xev->time=fake_timestamp();
345 xev->x=x; xev->y=y;
346 xev->x_root=1; xev->y_root=1;
347 xev->same_screen = True;
349 xev->state=0;
350 while ((part=strsep(&keyname, key_delimiter)))
352 part2=strncpy(part2,part,128);
353 // debugprintf("- %s \n",part);
354 kmlptr=keymodlist;
355 while (kmlptr->name)
357 // debugprintf("-- %s %s \n", kmlptr->name, part);
358 if (!strcasecmp(kmlptr->name, part))
359 xev->state|=kmlptr->mask;
360 kmlptr++;
362 // debugprintf("--- %s \n",part);
364 // debugprintf("*** %s \n",part);
365 // debugprintf("*** %s \n",part2);
366 xev->keycode=XKeysymToKeycode(dpy,XStringToKeysym(part2));
367 debugprintf("state 0x%x, keycode 0x%x\n",xev->state, xev->keycode);
368 free(part2);
369 return ;
372 void sendfocus(Window w,int in_out)
374 XFocusChangeEvent focev;
376 focev.display=dpy;
377 focev.type=in_out;
378 focev.window=w;
379 focev.mode=NotifyNormal;
380 focev.detail=NotifyPointer;
381 XSendEvent(dpy,w,True,FocusChangeMask,(XEvent*)&focev);
382 XSync(dpy,True);
384 return;
387 void sendpointer_enter_or_leave(Window w,int in_out)
389 XCrossingEvent crossev;
390 crossev.type=in_out;
391 crossev.display=dpy;
392 crossev.window=w;
393 crossev.root=root;
394 crossev.subwindow=None;
395 crossev.time=fake_timestamp();
396 crossev.x=1;
397 crossev.y=1;
398 crossev.x_root=1;
399 crossev.y_root=1;
400 crossev.mode=NotifyNormal;
401 crossev.detail=NotifyNonlinear;
402 crossev.same_screen=True;
403 crossev.focus=True;
404 crossev.state=0;
405 XSendEvent(dpy,w,True,EnterWindowMask|LeaveWindowMask,(XEvent*)&crossev);
406 XSync(dpy,True);
407 return;
410 void sendkey(char *keyname,int x,int y,Window w,Window s)
412 make_key(keyname ,x,y,(XKeyEvent*)&xev);
413 xev.xkey.window=w;
414 xev.xkey.subwindow=s;
416 if (s) sendfocus(s,FocusIn);
418 XSendEvent(dpy,w,True,KeyPressMask,&xev);
419 xev.type = KeyRelease;
420 usleep(2000);
421 xev.xkey.time = fake_timestamp();
422 if (s) sendfocus(s,FocusOut);
423 XSendEvent(dpy,w,True,KeyReleaseMask,&xev);
424 XSync(dpy,True);
425 return;
428 void sendbutton(int button, int x, int y, Window w,Window s)
430 make_button(button,x,y,(XButtonEvent*)&xev);
431 xev.xbutton.window=w;
432 xev.xbutton.subwindow=s;
433 sendpointer_enter_or_leave(w,EnterNotify);
434 sendpointer_enter_or_leave(s,EnterNotify);
436 XSendEvent(dpy,w,True,ButtonPressMask,&xev);
437 XSync(dpy,True);
438 xev.type = ButtonRelease;
439 xev.xkey.state|=0x100;
440 usleep(1000);
441 xev.xkey.time = fake_timestamp();
442 XSendEvent(dpy,w,True,ButtonReleaseMask,&xev);
443 sendpointer_enter_or_leave(s,LeaveNotify);
444 sendpointer_enter_or_leave(w,LeaveNotify);
445 XSync(dpy,True);
447 return;
451 int check(char *s)
453 int d;
454 char *buffer;
456 buffer=malloc(strlen(s));
457 if(buffer==NULL)
459 fprintf(stderr,"%s: out of memory\n",progname);
460 return(-1);
463 if(2!=sscanf(s,"Key %s %s\n",buffer,buffer) &&
464 4!=sscanf(s,"Button %d %d %d %s\n",&d,&d,&d,buffer) &&
465 4!=sscanf(s,"xy_Key %d %d %s %s\n",&d,&d,buffer,buffer))
467 fprintf(stderr,"%s: bad config string \"%s\"\n",progname,s);
468 free(buffer);
469 return(-1);
471 free(buffer);
472 return(0);
475 static struct option long_options[] =
477 {"help", no_argument, NULL, 'h'},
478 {"version", no_argument, NULL, 'V'},
479 {0, 0, 0, 0}
482 int main(int argc, char *argv[])
484 char keyname[128];
485 int pointer_button,pointer_x,pointer_y;
486 char windowname[64];
487 char *command=NULL;
488 int c;
490 char *ir;
491 int ret;
493 progname=argv[0];
495 while ((c = getopt_long(argc, argv, "hV", long_options, NULL)) != EOF) {
496 switch (c) {
497 case 'h':
498 printf("Usage: %s [command]\n", argv[0]);
499 printf("\t -h --help \t\tdisplay usage summary\n");
500 printf("\t -V --version \t\tdisplay version\n");
501 return(EXIT_SUCCESS);
502 case 'V':
503 printf("%s %s\n", progname, VERSION);
504 return(EXIT_SUCCESS);
505 case '?':
506 fprintf(stderr, "unrecognized option: -%c\n", optopt);
507 fprintf(stderr, "Try `%s --help' for more information.\n", progname);
508 return(EXIT_FAILURE);
512 if (argc == optind+1){
513 command = argv[optind];
514 } else if (argc > optind+1){
515 fprintf(stderr, "%s: incorrect number of arguments.\n", progname);
516 fprintf(stderr, "Try `%s --help' for more information.\n", progname);
517 return(EXIT_FAILURE);
520 dpy=XOpenDisplay(NULL);
521 if(dpy==NULL) {
522 fprintf(stderr,"Can't open DISPLAY.\n");
523 exit(1);
525 root=RootWindow(dpy,DefaultScreen(dpy));
527 if(2==sscanf(command,"Key %s %s\n",keyname,windowname))
529 if((w=find_window(root,windowname)))
531 debugprintf("keyname: %s \t windowname: %s\n",keyname,windowname);
532 sendkey(keyname,1,1,w,0);
534 else
536 debugprintf("target window '%s' not found \n",windowname);
539 else if(4==sscanf(command,"Button %d %d %d %s\n",
540 &pointer_button,&pointer_x,
541 &pointer_y,windowname))
543 if((w=find_window(root,windowname)) &&
544 (subw=find_sub_window(root,windowname,&pointer_x,&pointer_y)))
546 if (w==subw) subw=0;
547 debugprintf(" %s\n",command);
548 sendbutton(pointer_button,pointer_x,pointer_y,w,subw);
550 else
552 debugprintf("target window '%s' not found \n",windowname);
555 else if(4==sscanf(command,"xy_Key %d %d %s %s\n",
556 &pointer_x,&pointer_y,
557 keyname,windowname))
560 if((w=find_window(root,windowname))&& (subw=find_sub_window(root,windowname,&pointer_x,&pointer_y)))
562 debugprintf(" %s\n",command);
563 if (w==subw) subw=0;
564 sendkey(keyname,pointer_x,pointer_y,w,subw);
566 else
568 debugprintf("target window '%s' not found \n",windowname);
571 exit(0);
575 * Local variables:
576 * compile-command: "gcc -L/usr/X11R6/lib -lX11 -o sendxevent sendxevent.c"
577 * End: