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)
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 :*)
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?)
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
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.
69 * -fixed a stupid string bug in key sending.
70 * -updated irxevent.README to be up to date with the .lircrc format.
73 * -changed DEBUG functions to actually produce some output :)
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
101 #include <sys/socket.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>
113 void debugprintf(char *format_str
, ...)
116 va_start(ap
,format_str
);
117 vfprintf(stderr
,format_str
,ap
);
121 void debugprintf(char *format_str
, ...)
127 struct keymodlist_t
{
131 static struct keymodlist_t keymodlist
[]=
133 {"SHIFT", ShiftMask
},
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
},
144 const char *key_delimiter
="-";
145 const char *active_window_name
="CurrentWindow";
146 const char *root_window_name
="RootWindow";
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 */
162 struct timezone tz
; /* is not used since ages */
163 gettimeofday(&tv
,&tz
);
164 tint
=(int)tv
.tv_sec
*1000;
166 tint
=tint
+tv
.tv_usec
/1000;
170 Window
find_window(Window top
,char *name
)
174 Window
*children
,foo
;
175 int revert_to_return
;
177 if (!strcmp(active_window_name
,name
)){
178 XGetInputFocus(dpy
, &foo
, &revert_to_return
);
180 } else if(!strcmp(root_window_name
,name
)){
183 /* First the base case */
184 if (XFetchName(dpy
,top
,&wname
)){
185 if (!strncmp(wname
,name
,strlen(name
))) {
187 debugprintf("found it by wname %x \n",top
);
188 return(top
); /* found it! */
193 if(XGetIconName(dpy
,top
,&iname
)){
194 if (!strncmp(iname
,name
,strlen(name
))) {
196 debugprintf("found it by iname %x \n",top
);
197 return(top
); /* found it! */
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 */
222 top
= find_window(children
[nc
-1],name
);
223 if(top
) break; /* we found it somewhere */
225 if(children
!=NULL
) XFree(children
);
229 Window
find_sub_sub_window(Window top
,int *x
, int *y
)
232 Window
*children
,foo
,target
=0;
234 rel_x
,rel_y
,width
,height
,border
,depth
,
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 */
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
;
257 target
=find_sub_sub_window(target
,&new_x
,&new_y
);
262 if(children
!=NULL
) XFree(children
);
273 Window
find_sub_window(Window top
,char *name
,int *x
, int *y
)
276 Window
*children
,foo
,target
=0;
278 rel_x
,rel_y
,width
,height
,border
,depth
,
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 */
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
;
301 target
=find_sub_sub_window(target
,&new_x
,&new_y
);
306 if(children
!=NULL
) XFree(children
);
316 void make_button(int button
,int x
,int y
,XButtonEvent
*xev
)
318 xev
->type
= ButtonPress
;
322 xev
->time
=fake_timestamp();
324 xev
->x_root
=1; xev
->y_root
=1;
327 xev
->same_screen
=True
;
332 void make_key(char *keyname
,int x
, int y
,XKeyEvent
*xev
)
335 struct keymodlist_t
*kmlptr
;
336 char tmpkeyname
[128];
337 strncpy(tmpkeyname
,keyname
,128);
340 xev
->type
= KeyPress
;
343 xev
->subwindow
= None
;
344 xev
->time
=fake_timestamp();
346 xev
->x_root
=1; xev
->y_root
=1;
347 xev
->same_screen
= True
;
350 while ((part
=strsep(&keyname
, key_delimiter
)))
352 part2
=strncpy(part2
,part
,128);
353 // debugprintf("- %s \n",part);
357 // debugprintf("-- %s %s \n", kmlptr->name, part);
358 if (!strcasecmp(kmlptr
->name
, part
))
359 xev
->state
|=kmlptr
->mask
;
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
);
372 void sendfocus(Window w
,int in_out
)
374 XFocusChangeEvent focev
;
379 focev
.mode
=NotifyNormal
;
380 focev
.detail
=NotifyPointer
;
381 XSendEvent(dpy
,w
,True
,FocusChangeMask
,(XEvent
*)&focev
);
387 void sendpointer_enter_or_leave(Window w
,int in_out
)
389 XCrossingEvent crossev
;
394 crossev
.subwindow
=None
;
395 crossev
.time
=fake_timestamp();
400 crossev
.mode
=NotifyNormal
;
401 crossev
.detail
=NotifyNonlinear
;
402 crossev
.same_screen
=True
;
405 XSendEvent(dpy
,w
,True
,EnterWindowMask
|LeaveWindowMask
,(XEvent
*)&crossev
);
410 void sendkey(char *keyname
,int x
,int y
,Window w
,Window s
)
412 make_key(keyname
,x
,y
,(XKeyEvent
*)&xev
);
414 xev
.xkey
.subwindow
=s
;
416 if (s
) sendfocus(s
,FocusIn
);
418 XSendEvent(dpy
,w
,True
,KeyPressMask
,&xev
);
419 xev
.type
= KeyRelease
;
421 xev
.xkey
.time
= fake_timestamp();
422 if (s
) sendfocus(s
,FocusOut
);
423 XSendEvent(dpy
,w
,True
,KeyReleaseMask
,&xev
);
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
);
438 xev
.type
= ButtonRelease
;
439 xev
.xkey
.state
|=0x100;
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
);
456 buffer
=malloc(strlen(s
));
459 fprintf(stderr
,"%s: out of memory\n",progname
);
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
);
475 static struct option long_options
[] =
477 {"help", no_argument
, NULL
, 'h'},
478 {"version", no_argument
, NULL
, 'V'},
482 int main(int argc
, char *argv
[])
485 int pointer_button
,pointer_x
,pointer_y
;
495 while ((c
= getopt_long(argc
, argv
, "hV", long_options
, NULL
)) != EOF
) {
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
);
503 printf("%s %s\n", progname
, VERSION
);
504 return(EXIT_SUCCESS
);
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
);
522 fprintf(stderr
,"Can't open DISPLAY.\n");
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);
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
)))
547 debugprintf(" %s\n",command
);
548 sendbutton(pointer_button
,pointer_x
,pointer_y
,w
,subw
);
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
,
560 if((w
=find_window(root
,windowname
))&& (subw
=find_sub_window(root
,windowname
,&pointer_x
,&pointer_y
)))
562 debugprintf(" %s\n",command
);
564 sendkey(keyname
,pointer_x
,pointer_y
,w
,subw
);
568 debugprintf("target window '%s' not found \n",windowname
);
576 * compile-command: "gcc -L/usr/X11R6/lib -lX11 -o sendxevent sendxevent.c"