/* XMonobut - Modify mouse button behaviour with keyboard.

   o Usage

   Hold selected key ( KEYSYM_TO_GRAB ) down and click mouse button for
   right click.
   Quickly press selected key once, then again holding down for middle click.

   o Compiling

   gcc -Wall XMonobut.c -o xmonobut -L/usr/X11R6/lib -lX11


   Copyright 2002 Matthew Allum <mallum@handhelds.org>

   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, 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.

	modified: Sat Apr  6 18:04:17 EST 2002 by dave.capella@cornell.edu
	for use on the ipaq. changed key code. replaced key codes w/macro.
	fixed bug in call to XSetPointerMapping. lengthened double-click time.
	added code to make code selectable on command line.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xmd.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>

/* get from xev or keysym.h  */
#define KEYSYM_TO_GRAB 130   /* ipaq: calendar */
#define DCLICK_TIME    500

int main(int argc, char **argv)
{
   Display *dpy;
   char *dpy_name = NULL;
   Window root;
   XEvent ev;
   Cursor right_curs, middle_curs, orig_curs;
   Time lasttime = 0;
/* dwc - what is the max???
   unsigned char map[5];
*/
   unsigned char map[24];
   int nmap;
   int keycode = KEYSYM_TO_GRAB;

	/* can be called as: xmonobtn mail for instance */
	if(argc == 2) {
		if(!strcmp(argv[1],"calendar")) { keycode = 130; }
		else if(!strcmp(argv[1],"phone")) { keycode = 131; }
		else if(!strcmp(argv[1],"mail")) { keycode = 132; }
		else if(!strcmp(argv[1],"start")) { keycode = 133; }
		else if(!strcmp(argv[1],"record")) { keycode = 128; }
		else { keycode = atoi(argv[1]); }
		if(!keycode) {
			fprintf(stderr,"invalid keycode\n");
			exit(1);
		}
		fprintf(stderr,"keycode: %d\n",keycode);
	}

   if ((dpy = XOpenDisplay(dpy_name)) == NULL) {
      fprintf(stderr, "can't open display! check your DISPLAY variable.\n");
      exit(1);
   }
   root = RootWindow(dpy, DefaultScreen(dpy));

   /* see http://tronche.com/gui/x/xlib/appendix/b/ for more cursors */
   right_curs  = XCreateFontCursor(dpy, XC_mouse);
   middle_curs = XCreateFontCursor(dpy, XC_gumby);    /* :) */
   orig_curs   = XCreateFontCursor(dpy, XC_left_ptr);

   XGrabKey(dpy, keycode, 0 /*XKeysymToKeycode(dpy, KEYSYM_TO_GRAB), AnyModifier*/ ,
            root, True, GrabModeAsync, GrabModeAsync);

   XSelectInput(dpy, root, KeyPressMask | KeyReleaseMask );

   for (;;) {
      XNextEvent(dpy, &ev);
      switch (ev.type) {
         case KeyPress:
		/* dwc */
	    /* fprintf(stderr,"got keypress: %d\n",ev.xkey.keycode); */
            if (ev.xkey.keycode != keycode) break;
            XAutoRepeatOff(dpy);
            nmap = XGetPointerMapping(dpy, map, 3);
            if (lasttime && (ev.xkey.time-lasttime < DCLICK_TIME) )
            {  /* double press - remap for middle button  */
               map[0] = (unsigned char) 2;
               map[1] = (unsigned char) 3;
               map[2] = (unsigned char) 1;
               XDefineCursor(dpy, root, middle_curs);
            } else {
               map[0] = (unsigned char) 3;
               map[1] = (unsigned char) 2;
               map[2] = (unsigned char) 1;
               XDefineCursor(dpy, root, right_curs);
            }
            lasttime = ev.xkey.time;
            XSetPointerMapping(dpy, map, nmap);
            break;

         case KeyRelease:
            if (ev.xkey.keycode != keycode) break;
            /* Put everything back to normal */
            map[0] = (unsigned char) 1;
            map[1] = (unsigned char) 2;
            map[2] = (unsigned char) 3;
            XSetPointerMapping(dpy, map, nmap);
            XDefineCursor(dpy, root, orig_curs);
            XAutoRepeatOn(dpy);
            break;

        }
    }

   XUngrabKey(dpy, keycode /* XKeysymToKeycode(dpy, KEYSYM_TO_GRAB) */, AnyModifier, root);
   XCloseDisplay(dpy);
}


