#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	mainkey.c (Main Key)
 * Purpose:	Dispatch responses mapped to various keyboard keys
 * Subroutine:	key_response()			returns: void
 * Subroutine:	set_iraf_key_trigger()		returns: void
 * Xlib calls:	XWarpPointer(), XSync()
 * Copyright:	2003 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 */

#include <stdio.h>
#include <X11/Xlib.h>		/*  X window stuff  */
#include <X11/Xutil.h>		/*  X window manager stuff  */
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include "hfiles/constant.h"	/*  Define codes  */
#include "hfiles/struct.h"	/*  Declare structure types  */
#include "hfiles/extern.h"	/*  Extern main parameter structures  */

#define MAX_MAPPED_STRING_LENGTH 16
#define MetaMask Mod1Mask


#ifdef ANSIC
/*  Exported declarations must be centralized before ANSI C can be used  */

void		grab_keys_for_textcursor(	int state);
void		set_iraf_key_trigger(	int state);
void		key_response();
void          set_zoom (double zoom_factor, int *direction, double xzoom,
                        double yzoom);
#else
void          set_zoom ();
#endif


static int textcursor = 0;
/*  Subroutine:	grab_keys_for_textcursor
 *  Purpose:	Direct all key input to the text cursor editor
 */
#ifdef ANSIC
void
grab_keys_for_textcursor ( int state )
#else
void
grab_keys_for_textcursor ( state )
     int state;
#endif
{
  textcursor = state;
}


#ifdef IMTOOL
static int
iraf_trigger = 0;
/*  Subroutine:	set_iraf_key_trigger
 *  Purpose:	Set and clear trigger for cursor readback through IRAF pipe
 */
#ifdef ANSIC
void
set_iraf_key_trigger ( int state )
#else
void
set_iraf_key_trigger ( state )
     int state;
#endif
{
  iraf_trigger = state;
}
#endif

static int direction = 1;
static double oldxpix = 0.0;
static double oldypix = 0.0;

/*  Subroutine:	key_response
 *  Purpose:	Respond to a key stroke
 */

static double oldxpos, oldypos;

static void PrintFITSHead();
static int new_image();

void
key_response()
{
  KeySym keysym;
  XComposeStatus compose;
  int char_cnt;
  int x, y;
  char vstring[16];
  char string[16];
  int ix,iy,lstr;
  int quadcube;
  double xcent,ycent;
  static int bufsize = MAX_MAPPED_STRING_LENGTH;
  char buffer[MAX_MAPPED_STRING_LENGTH];
#ifdef IMTOOL
  int trigger_curpos_to_iraf();
#endif
  void magnify_pan(), magnify_disp(), say_goodbye(), disp_panbox();
  void disp_dispbox(), raise_windows(), get_new_cmd(), print_table();
  void ascii_region(), textcursor_keyentry();
  void print_center(), print_cursor();
  void move_pointer();
  void get_cursor_pos();
  void toggle_region_visibility(), toggle_region_labeling();
  double xbuf, ybuf, xfile, yfile;
  double newxpos, newypos, distance;
  char sysout0[16];
  char wcstr[32];
  int lwcstr = 32;

  if (iswcs(wcs) && (wcs->prjcode == WCS_CSC ||
      wcs->prjcode == WCS_QSC || wcs->prjcode == WCS_TSC))
    quadcube = 1;
  else
    quadcube = 0;

  /*  Decode the key event to ascii  */
  char_cnt = XLookupString(&control.event.xkey, buffer, bufsize,
			   &keysym, &compose);
  /*  Key input from display window may be redirected for special purposes  */
  if( control.event.xkey.window == dispbox.ID ) {
#ifdef IMTOOL
    if( iraf_trigger && (char_cnt == 1) &&
	trigger_curpos_to_iraf(&control.event.xkey, (int)buffer[0]) )
      return;
#endif
    /*  Redirect keyboard input for textcursor editor  */
    if( textcursor ) {
      textcursor_keyentry(&control.event.xkey, keysym);
      return;
    }
  }
  /*  Ignore modifier key pressing  */
  if( ((control.event.xkey.state & (ControlMask | MetaMask)) == 0) ||
      (keysym >= XK_BackSpace) ) {
    switch( keysym ) {

    /*  Don't update tracking now if in IRAF interactive mode  */
    case XK_Shift_L:
    case XK_Shift_R:
#ifdef IMTOOL
      if( iraf_trigger )
	return;
#endif
      if( control.event.xkey.window == panbox.ID ) {
	/*  Update magnifier if in panbox  */
	magnify_pan (&control.event);
      } else if( (control.event.xkey.window == dispbox.ID) &&
		 (!control.magni_track) ) {
	/*  If in disp window and not now tracking, update magnifier  */
	magnify_disp (&control.event, 1, !control.coord_track);
      }
      break;

#ifdef SUN
      /*  Shifted arrow keys on Sun keypad  */
    case XK_R8:
    case XK_R10:
    case XK_R12:
    case XK_R14:
      if( keysym == XK_R8 )
	keysym = XK_Up;
      else if( keysym == XK_R10 )
	keysym = XK_Left;
      else if( keysym == XK_R12 )
	keysym = XK_Right;
      else if( keysym == XK_R14 )
	keysym = XK_Down;
#endif

    /*  Use the mouse coordinates at time of key strike  */
    case XK_Up:
    case XK_Down:
    case XK_Left:
    case XK_Right:
      if( keysym == XK_Up )
	y = control.event.xkey.y - 1;
      else if( keysym == XK_Down )
	y = control.event.xkey.y + 1;
      else
	y = control.event.xkey.y;
      if( keysym == XK_Right )
	x = control.event.xkey.x + 1;
      else if( keysym == XK_Left )
	x = control.event.xkey.x - 1;
      else
	x = control.event.xkey.x;

      /*  Move the mouse (supercede any recent mouse movement)  */
      XSync (control.event.xkey.display, 0);
      XWarpPointer(control.event.xkey.display, None,
		   control.event.xkey.window, 0, 0, 0, 0, x, y);
      break;

    /* Center cursor in image  */
    case XK_Home:
      move_pointer (control.event.xkey.display, control.event.xkey.window,
		    img.filecols/2, img.filerows/2);
      break;

    /* Raise all windows out of chaos */
    case XK_A:
    case XK_a:
      disp_panbox();
      disp_dispbox();
      raise_windows();
      break;

    /*  Debugging print_table without scaling (fool it about scaling)  */
    case XK_L:
    case XK_l:
      x = img.fiscaled;
      img.fiscaled = 0;
      print_table();
      img.fiscaled = x;
      break;

    /*  Open a new image file (see CmdNew.c)  */
    case XK_N:
    case XK_n:
      get_new_cmd();
      break;

/* #ifdef QUITKEY */
    case XK_Q:
    case XK_q:
      /*  q FOR QUIT  */
      if (!img.imtool_200)
	say_goodbye(0);
      break;
/* #endif */

    case XK_R:
    case XK_r:
      raise_windows();
      break;

    /*  Print table of image values if in display or pan windows  */
    case XK_T:
    case XK_t:
      print_table();
      break;

    /*  Character control in region (cursor) mode  */
    case XK_Delete:
    case XK_D:
    case XK_d:
    case XK_E:
    case XK_e:
    case XK_S:
    case XK_s:
      if (control.mode == COP ) {
	if ((control.event.xkey.window == dispbox.ID) ||
	    (cursor.type == COP_Text) )
	  ascii_region(&control.event.xkey, keysym);
	}
      else if (keysym == XK_E || keysym == XK_e) {
	wcsoutinit (wcs,"ECLIPTIC");
	magnify_disp (&control.event, 0, 1);
	}
      break;

    /* Toggle region visibility */ 
    case XK_bracketleft:
      toggle_region_visibility();
      break;

    /* Toggle region labelling */ 
    case XK_bracketright:
      toggle_region_labeling();
      break;

    /* Read next image in a 3-D image */ 
    case XK_plus:
    case XK_equal:
      if (img.nimage < img.filenimg) {
	img.nimage = img.nimage + 1;
	if (quadcube)
	  (void)wcszin (img.nimage-1);
	else
	  (void)wcszin (img.nimage);
	(void)new_image();
	magnify_disp (&control.event, 0, 1);
	}
      break;

    /* Read previous image in a 3-D image */ 
    case XK_minus:
      if (img.nimage > 1) {
	img.nimage = img.nimage - 1;
	(void)new_image();
	if (quadcube)
	  (void)wcszin (img.nimage-1);
	else
	  (void)wcszin (img.nimage);
	magnify_disp (&control.event, 0, 1);
	}
      break;

    /* Print current FITS header to standard output */
    case XK_F:
    case XK_f:
	PrintFITSHead (img.header);
	break;

    /* save current cursor position within image in pixel list file */
    case XK_P:
    case XK_p:

    /* Center image at zoom 1x */
    case XK_0:
	if (quadcube) {
	    (void)wcszin (0);
	    img.nimage = 1;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (0.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to first image or zoom 1x */
    case XK_1:
	if (img.filenimg > 1) {
	    (void)wcszin (1);
	    if (quadcube)
		img.nimage = 2;
	    else
		img.nimage = 1;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (1.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to second image or zoom 2x */
    case XK_2:
	if (img.filenimg > 1) {
	    (void)wcszin (2);
	    if (quadcube)
		img.nimage = 3;
	    else
		img.nimage = 2;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (2.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to third image or zoom 3x */
    case XK_3:
	if (img.filenimg > 2) {
	    (void)wcszin (3);
	    if (quadcube)
		img.nimage = 4;
	    else
		img.nimage = 3;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (3.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to fourth image or zoom 4x */
    case XK_4:
	if (img.filenimg > 3) {
	    (void)wcszin (4);
	    if (quadcube)
		img.nimage = 5;
	    else
		img.nimage = 4;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (4.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to fifth image or zoom 5x */
    case XK_5:
	if (img.filenimg > 4) {
	    (void)wcszin (5);
	    if (quadcube)
		img.nimage = 6;
	    else
		img.nimage = 5;
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (5.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to sixth image or zoom 6x */
    case XK_6:
	if (img.filenimg > 5 && !quadcube) {
	    img.nimage = 6;
	    (void)wcszin (img.nimage);
	    (void)new_image();
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (6.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to seventh image or zoom 7x */
    case XK_7:
	if (img.filenimg > 6) {
	    img.nimage = 7;
	    (void)new_image();
	    (void)wcszin (img.nimage);
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (7.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to eighth image or zoom 8x */
    case XK_8:
	if (img.filenimg > 7) {
	    img.nimage = 8;
	    (void)new_image();
	    (void)wcszin (img.nimage);
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    direction = 1.0;
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (8.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Move directly to ninth image or zoom 9x */
    case XK_9:
	if (img.filenimg > 8) {
	    img.nimage = 9;
	    (void)new_image();
	    (void)wcszin (img.nimage);
	    magnify_disp (&control.event, 0, 1);
	    }
	else if (img.filenimg < 2) {
	    direction = 1.0;
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    set_zoom (9.0, &direction, xbuf, ybuf);
	    }
	break;

    /* Change coordinate system in which cursor tracking is occurring */
    case XK_B:
    case XK_b:
	wcsoutinit (wcs,"B1950");
	magnify_disp (&control.event, 0, 1);
	break;
    case XK_G:
    case XK_g:
	wcsoutinit (wcs,"GALACTIC");
	magnify_disp (&control.event, 0, 1);
	break;
    case XK_I:
    case XK_i:
	wcsoutinit (wcs,"imsys");
	magnify_disp (&control.event, 0, 1);
	break;
    case XK_J:
    case XK_j:
	wcsoutinit (wcs,"J2000");
	magnify_disp (&control.event, 0, 1);
	break;

    /* Toggle WCS output between degrees and h:m:s d:m:s */
    case XK_H:
    case XK_h:
	if (iswcs (wcs)) {
	    if (wcs->degout) {
		wcs->degout = 0;
		wcs->ndec = 3;
		}
	    else {
		wcs->degout = 1;
		wcs->ndec = 6;
		}
	    }
	magnify_disp (&control.event, 0, 1);
	break;

    /* Print cursor position to standard output */
    case XK_C:
    case XK_c:
	print_cursor (&control.event, 1);
	if (iswcs (wcs)) {
	    oldxpos = wcs->xpos;
	    oldypos = wcs->ypos;
	    oldxpix = wcs->xpix;
	    oldypix = wcs->ypix;
	    }
	break;

    /* Print distance since last cursor position to standard output */
    case XK_V:
    case XK_v:
	if (iswcs (wcs)) {
	    print_cursor (&control.event, 1);
	    newxpos = wcs->xpos;
	    newypos = wcs->ypos;
	    distance = wcsdist (oldxpos, oldypos, newxpos, newypos);
	    if (distance < 1.0) {
		printf ("Separation is %.3f arcseconds\n", distance*3600.0);
		printf ("dRA = %.3f arcsec, dDec = %.3f arcsec\n",
                   (newxpos-oldxpos)*3600.0 * cosdeg (0.5 * (oldypos+newypos)),
                   (newypos - oldypos) * 3600.0);
		}
	    else {
		printf ("Separation is %.5f degrees\n", distance);
		printf ("dRA = %.5f degrees, dDec = %.5f degrees\n",
                   (newxpos-oldxpos) * cosdeg (0.5 * (oldypos+newypos)),
                   (newypos - oldypos));
		}
	    oldxpos = wcs->xpos;
	    oldypos = wcs->ypos;
	    }
	break;

    /* Use WCS and image coordinates of cursor with an external command */
    case XK_W:
    case XK_w:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event,&xbuf,&ybuf,&xfile,&yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    if (oldxpix != 0.0 && oldypix != 0.0) {
		wcscom (wcs, 0, img.filename, oldxpix, oldypix, wcstr);
		oldxpix = 0.0;
		oldypix = 0.0;
		}
	    else {
		wcscom (wcs, 0, img.filename, xfile, yfile, wcstr);
		}
	    }
	break;

    case XK_X:
    case XK_x:
	print_center (&oldxpix, &oldypix);
	break;

    /* Toggle between AIPS and WCSLIB WCS subroutines */
    case XK_Z:
	if (iswcs (wcs)) {
	    if (wcs->wcsproj == WCS_BEST)
		wcs->wcsproj = WCS_ALT;
	    else
		wcs->wcsproj = WCS_BEST;
	    }
	magnify_disp (&control.event, 0, 1);
	break;

    case XK_z:
	set_zoom (99.0, &direction, xbuf, ybuf);
	break;

    /* Use WCS and image coordinates of cursor with an external command */
    case XK_F1:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 1, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F2:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 2, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F3:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 3, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F4:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 4, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F5:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 5, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F6:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 6, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F7:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 7, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F8:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 8, img.filename, xfile, yfile, wcstr);
	    }
	break;
    case XK_F9:
	if (iswcs (wcs)) {
	    (void)get_cursor_pos (&control.event, &xbuf, &ybuf, &xfile, &yfile);
	    pix2wcst (wcs, xfile, yfile, wcstr, lwcstr);
	    wcscom (wcs, 9, img.filename, xfile, yfile, wcstr);
	    }
	break;

    /* Print all cursor commands to standard output */
    case XK_question:
	printf ("SAOimage keyboard commands:\n");
	printf ("A rAises all SAOimage windows to the top and refresh\n");
	printf ("B tracks coordinates of cursor in B1950 (FK4) coordinates\n");
	printf ("C prints Coordinates of cursor (x,y, current WCS if present)\n");
	printf ("D Deletes the smallest region enclosing the mouse\n");
	printf ("E tracks cursor coordinates in Ecliptic coordinates\n");
	printf ("  saves current cursor as an excluded region in Region mode\n");
	printf ("F print FITS header to standard output (for .imh images, too)\n");
	printf ("G tracks cursor coordinates in Galactic coordinates\n");
	printf ("H toggles cursor coordinates between degrees and hh: dd: \n");
	printf ("I tracks cursor coordinates in coordinate system of image\n");
	printf ("J tracks cursor coordinates in J2000 (FK5) coordinates\n");
	printf ("L prints table of pixels values around mouse without scaling\n");
	printf ("N enters New command-line arguments\n");
	printf ("Q Quits SAOimage\n");
	printf ("R Raises all SAOimage windows to the top\n");
	printf ("S Saves current cursor as an included region\n");
	printf ("T prints table of the pixel values around current mouse position\n");
	printf ("V prints distance since last position, assuming same system\n");
	printf ("W executes WCS command\n");
	printf ("X prints centroid coordinates of cursor (X,y, WCS if present)\n");
	printf ("z zooms in and out by factor of two each time it is pressed\n");
	printf ("+ or = gets next image from 3-D image file\n");
	printf ("- gets previous image from 3-D image file\n");
	printf ("1-9 gets nth image from 3-D image file or zooms n times\n");
	printf ("[ toggles display of regions or overplotted catalogs\n");
	printf ("] toggles display of labels of regions or overplotted catalogs\n");
	printf ("shift stops tracking while cursor is moved\n");
	printf ("arrow keys move the cursor\n");
	break;

    default:
      break;
    }
  }
}

/*
 * Subroutine:  new_image
 * Purpose:     Having the image record set, do all that is needed to load
 *              a new image from the same file
 */
static int new_image ( )
{
  int init_image(), init_imagebuf();
  void set_tdisp(), new_display(), new_panbox(), disp_panbox();

  /* get the image dimensions (need file name, type) */
  if( init_image() == 0 )
    return(0);
  /* resize the image buffer */
  (void)init_imagebuf();
  /* set display params and force reassessing and rescaling the image */
  set_tdisp(&coord);
  buffer.mm.img_leftX = coord.id.srcX1 + 1;
  /* read new image data */
  new_display(1, 1, 1, 1);
  /* replace the panbox with a new one */
  new_panbox(1);
  disp_panbox();
  return( 1 );
}

#ifdef ANSIC
static void
PrintFITSHead (char *header)
#else
static void
PrintFITSHead (header)
  char    *header;        /* Image FITS header */
#endif
{
    char line[80], *iline, *endhead;
    int i, nblank;

    endhead = ksearch (header, "END") + 80;
    if (endhead == NULL)
        return;

    nblank = 0;
    for (iline = header; iline < endhead; iline = iline + 80) {
        strncpy (line, iline, 80);
        i = 79;
        while (line[i] <= 32 && i > 0)
            line[i--] = 0;
        if (i > 0) {
            if (nblank > 1) {
                printf ("COMMENT   %d blank lines\n",nblank);
                nblank = 0;
                }
            else if (nblank > 0) {
                printf ("COMMENT   %d blank line\n",nblank);
                nblank = 0;
                }
            printf ("%s\n",line);
            }
        else
            nblank++;
        }

    return;
}
/* June 29 1989	Michael VanHilst	initial version
 * Aug 16 1989	MVH display window key to trigger IRAF write
 *
 * Jun  1 1991	MVH support for text cursor
 *
 * Oct 27 1994	Doug Mink - support for centroid
 *
 * Jun 21 1995	DJM - add help
 * Jul  6 1995	DJM - reword wcs calls
 * Aug 17 1995	DJM - add coordinate conversion
 *
 * Jan 24 1996	DJM - only change system for J,G,B
 * Feb  9 1996	DJM - Do not quit with q if imtool
 * Sep  6 1996	DJM - Pass filename to wcscom()
 *
 * Feb 18 1998	DJM - Switch between WCS subroutines
 * Apr 14 1998	DJM - Add e for ecliptic coordinates
 * May 13 1998	DJM - Add i for image coordinate system
 * May 29 1998	DJM - Add h for degree/hms toggling
 * Jul 13 1998	DJM - Call wcszin() when changing frame
 * Jul 16 1998	DJM - Add get nth frame option
 * Aug  6 1998	DJM - Add get center option
 * Aug 14 1998	DJM - Add function key commands
 * Sep 29 1998	DJM - Add distance option
 * Oct 14 1998	DJM - Add [ ] to toggle region labels
 * Oct 14 1998	DJM - Add f to print FITS header
 * Oct 23 1998	DJM - Add z to zoom in and out
 * Oct 23 1998	DJM - Zoom with 1-9 if 2-d image
 * Nov  6 1998	DJM - Add 0 zoom and recenter
 * Nov 30 1998	Paul Sydney - Fix set_zoom() calls
 * Nov 30 1998	DJM - Add back region exculsion control
 *
 * Feb 23 1999	DJM - Set face for quad cube projections in +-012345
 * Aug 16 1999	DJM - Set number of decimal places when toggling with H
 * Aug 20 1999	DJM - Add WCS string argument to wcscom(); decouple X Y
 * Aug 20 1999	DJM - Add coordinate return from print_center()
 * Aug 23 1999	DJM - Fix bug in oldxpix,oldypix saving
 *
 * Apr 23 2002	DJM - Fix bug so distance in arcsec really is
 *
 * Sep 24 2003	DJM - Improve V command to print dRA and dDec
 */


syntax highlighted by Code2HTML, v. 0.9.1