commit 6c3aa3e74d44f929f92eaf7cd4faa0d91017de88 Author: Nicolas MASSE Date: Wed Sep 11 12:12:43 2019 +0200 migration from svn diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e7bec3f --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +LDFLAGS = -lX11 -L/usr/X11R6/lib +CFLAGS = -Wall + +all: xspy + +clean: + rm -f *.o xspy + +.PHONY: all clean + diff --git a/xspy.c b/xspy.c new file mode 100644 index 0000000..ec21efc --- /dev/null +++ b/xspy.c @@ -0,0 +1,309 @@ +/* + * XSpy - Spies a window for key events. + * Copyright (C) 2006 Nicolas MASSE + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +/* Defines the behavior of the program : windows list or window spy */ +typedef enum {MODE_LIST = 0, MODE_SPY = 1} Mode; + + +/** + * Prints the details about the window. + * + * @param dsp the display. + * @param w the window. + * @param depth the depth in the window stack. + */ +void PrintWindow(Display * dsp, Window w, int depth) { + int i; + char * name; + + /* indent */ + for (i = 0; i < depth; i++) { + printf(" "); + } + + printf("%#.8lx - ", w); + + /* Display the window title */ + int res = XFetchName(dsp, w, &name); + if (res) { + printf("\"%s\"", name); + } else { + printf("(has no name)"); + } + XFree(name); + + printf("\n"); +} + +/** + * Lists recursively all the windows of the display. + * + * @param dsp the display. + * @param w the parent window. + * @param depth the depth in the window stack. + */ +void ListWindows(Display * dsp, Window w, int depth) { + Window rootWindow; + Window * windowsList; + Window parentWindow; + unsigned int nWindows; + + int res = XQueryTree( + dsp, /* Display */ + w, /* Window */ + &rootWindow, /* Root window */ + &parentWindow, /* Parent window */ + &windowsList, /* Windows list */ + &nWindows /* Number of child windows */ + ); + + if (res) { + int i; + + for (i = 0; i < nWindows; i++) { + PrintWindow(dsp, windowsList[i], depth); + ListWindows(dsp, windowsList[i], depth + 1); + } + + XFree(windowsList); + } +} + +/** + * Lists all the windows of the connected display to the standard output. + * + * @param dsp the display + */ +void ListAllWindows(Display * dsp) { + /* Print the root window */ + Window w = DefaultRootWindow(dsp); + PrintWindow(dsp, w, 0); + + /* List all subwindows recursively */ + ListWindows(dsp, w, 1); +} + +/** + * Listens to the window w. + * + * @param dsp the display + * @param w the window + */ +void RegisterListener(Display * dsp, Window w) { + /* Select useful events */ + XSelectInput(dsp, w, KeyPressMask|KeyReleaseMask); +} + +/** + * Recursively registers the listeners using w as root window. + * + * @param dsp the display + * @param w the root window + */ +void RegisterListeners(Display * dsp, Window w) { + Window rootWindow; + Window * windowsList; + Window parentWindow; + unsigned int nWindows; + + int res = XQueryTree( + dsp, /* Display */ + w, /* Window */ + &rootWindow, /* Root window */ + &parentWindow, /* Parent window */ + &windowsList, /* Windows list */ + &nWindows /* Number of child windows */ + ); + + if (res) { + int i; + + for (i = 0; i < nWindows; i++) { + RegisterListener(dsp, windowsList[i]); + RegisterListeners(dsp, windowsList[i]); + } + + XFree(windowsList); + } + +} + +/** + * Registers all the listeners. + * + * @param dsp the display. + */ +void RegisterAllListeners(Display * dsp) { + /* Register the root window */ + Window w = DefaultRootWindow(dsp); + RegisterListener(dsp, w); + + /* Register all subwindows recursively */ + RegisterListeners(dsp, w); + +} + +/** + * Endless loop which waits for key events and prints them on the standard + * output. + * + * @param dsp the display. + */ +void WaitForKeys(Display * dsp) { + XEvent evt; + XKeyEvent * kevt = (XKeyEvent *) &evt; + KeySym key; + char key_str[256]; + size_t size; + + while (1) { + /* Wait for an event */ + XNextEvent(dsp, &evt); + + switch (evt.type) { + case KeyPress: + case KeyRelease: + /* Retrieve information about the event */ + size = XLookupString(kevt, key_str, 256, &key, 0); + key_str[size] = '\0'; + + printf("%#.8lx: ", kevt->window); + + if (evt.type == KeyPress) { + printf("KeyPress: "); + } else { + printf("KeyRelease: "); + } + + /* Prints the key name */ + printf("%s\n", XKeysymToString(key)); + + break; + default: + printf("UnhandledEvent\n"); + break; + } + } +} + +/** + * Displays an help message and exits. + */ +void DisplayUsage(void) { + fprintf(stderr, "Usage: xspy {list | spy [window_id]| help}\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Valid modes :\n"); + fprintf(stderr, "\tlist : displays all windows of the display.\n"); + fprintf(stderr, "\tspy : listen the windows for key events.\n"); + fprintf(stderr, "\thelp : this help message.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Parameters :\n"); + fprintf(stderr, "\twindow_id : the id of the window to listen.\n"); + fprintf(stderr, "\t If not specified, listen to all windows\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "How to change the display ?\n"); + fprintf(stderr, "\t$ DISPLAY=host:display program\n"); + fprintf(stderr, "\tExample :\n"); + fprintf(stderr, "\t$ DISPLAY=tx10:0 xspy\n"); + exit(1); +} + +/** + * Parses the options of the program. + * + * @param argc the number of arguments + * @param argv an array of arguments. + * @param win a pointer to the window id to listen. + * @return the mode. + */ +Mode ParseOptions(int argc, char ** argv, Window * win) { + Mode mode = MODE_LIST; + + if (argc > 1) { + if (strcmp(argv[1], "list") == 0) { + mode = MODE_LIST; + } else if (strcmp(argv[1], "spy") == 0) { + mode = MODE_SPY; + if (argc != 3) { + *win = 0; + } else { + char * endPtr = NULL; + *win = strtol(argv[2], &endPtr, 16); + if (*endPtr != '\0') { + fprintf(stderr, "Unknown number: '%s'\n", argv[2]); + DisplayUsage(); + } + } + } else if (strcmp(argv[1], "help") == 0) { + DisplayUsage(); + } else { + fprintf(stderr, "Unknown mode '%s'\n", argv[1]); + DisplayUsage(); + } + } else { + DisplayUsage(); + } + + return mode; +} + +/** + * Entry point of the program. + * + * @return 0 + */ +int main(int argc, char ** argv) { + /* The window to listen */ + Window win; + + /* Reads options and sets global variables */ + Mode mode = ParseOptions(argc, argv, &win); + + Display * dsp = XOpenDisplay(NULL); + if (dsp == NULL) { + fprintf(stderr, "Unable to open display\n"); + exit(1); + } + + switch (mode) { + case MODE_LIST: + ListAllWindows(dsp); + break; + case MODE_SPY: + if (win == 0) { + RegisterAllListeners(dsp); + } else { + RegisterListener(dsp, win); + } + + WaitForKeys(dsp); + break; + } + + XCloseDisplay(dsp); + + return 0; +} +