#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