/*----------------------------------------------------------------------------*
 | This file is part of DEU (Doom Editing Utilities), created by the DEU team:|
 | Raphael Quinet, Brendon Wyber, Ted Vessenes and others.  See README.1ST or |
 | the "about" dialog box for full credits.                                   |
 |                                                                            |
 | DEU is an open project: if you think that you can contribute, please join  |
 | the DEU team.  You will be credited for any code (or ideas) included in    |
 | the next version of the program.                                           |
 |                                                                            |
 | If you want to make any modifications and re-distribute them on your own,  |
 | you must follow the conditions of the DEU license.  Read the file LICENSE  |
 | in this directory or README.1ST in the top directory.  If do not have a    |
 | copy of these files, you can request them from any member of the DEU team, |
 | or by mail: Raphael Quinet, Rue des Martyrs 9, B-4550 Nandrin (Belgium).   |
 |                                                                            |
 | This program comes with absolutely no warranty.  Use it at your own risks! |
 *----------------------------------------------------------------------------*

 G_GFXX11.C - Graphical routines for X-Window

 Functions written by Mike Thomas and Raphael Quinet
*/

/* the includes */
#include "deu.h"
#include <math.h>
#include <X11/Xlib.h>
#include <X11/StringDefs.h>
#include <X11/keysym.h>
#include "d_main.h"
#include "d_misc.h"
#include "d_config.h"
#include "d_wads.h"
#include "g_mouse.h"
#include "g_colcnv.h"
#include "g_gfx.h"

/* the global variables */
Int16  OrigX;         /* the X origin */
Int16  OrigY;         /* the Y origin */
float  Scale;         /* the scale value */
UInt16 PointerX;      /* X position of pointer */
UInt16 PointerY;      /* Y position of pointer */
UInt16 ScrMaxX;       /* maximum X screen coord */
UInt16 ScrMaxY;       /* maximum Y screen coord */
UInt16 ScrCenterX;    /* X coord of screen center */
UInt16 ScrCenterY;    /* Y coord of screen center */

/* private */
static int  current_color;      /* current color */
/* almost private: shared with g_colcnv.c */
int         num_colors = -1;    /* number of colors available */
/* almost private: shared with g_moux11.c */
Display     *x_display;
Window       x_win;
GC           x_gc;
Colormap     x_cmap;
XEvent       x_xev;
int          x_pointerx;
int          x_pointery;
unsigned int x_buttons;
unsigned int x_modifiers;
long         x_inputeventmask;

/*
   ...
*/

static void UpdateWindowSize(void)
{
  Window rwin;
  unsigned int junk;
  unsigned int lwidth;
  unsigned int lheight;

  XGetGeometry(x_display, x_win, &rwin, &junk, &junk,
	       &lwidth, &lheight, &junk, &junk);
  ScrMaxX = (UInt16)lwidth - 1;
  ScrMaxY = (UInt16)lheight - 1;
  ScrCenterX = ScrMaxX / 2;
  ScrCenterY = ScrMaxY / 2;
}


/*
   Initialise the graphics display.
*/

void InitGfx(void)
{
  int               screen;
  XFontStruct      *xfs;
  XWindowAttributes xwa;

  x_display = XOpenDisplay(NULL);
  if (x_display == NULL)
    ProgError("Cannot open display");
   
  screen = DefaultScreen(x_display);
  x_win = XCreateSimpleWindow(x_display, RootWindow(x_display, screen),
			      0, 0, 800, 600, 0, 0, 0);
  XStoreName(x_display, x_win, DEU_VERSION);
  x_gc = XCreateGC(x_display, x_win, 0, 0);

  num_colors = 256; /* maybe support other visuals later? */
  if (num_colors >= 256)
    {
      XGetWindowAttributes(x_display, x_win, &xwa);
      x_cmap = XCreateColormap(x_display, x_win, xwa.visual, AllocAll);
      SetDoomPalette(0);
      XSetWindowColormap(x_display, x_win, x_cmap);
    }
  SetColor(WHITE);

  XSelectInput(x_display, x_win, ExposureMask);
  XMapRaised(x_display, x_win);

  xfs = XLoadQueryFont(x_display, "pc8x8");
  if (xfs == NULL)
    ProgError("Cannot load font pc8x8.  Check your fontpath");
  XSetFont(x_display, x_gc, xfs->fid);

  /* wait for the first Expose event */
  XWindowEvent(x_display, x_win, ExposureMask, &x_xev);
  UpdateWindowSize();
  InitMouseDriver();
  if (UseMouse)
    {
      ResetMouseLimits();
      SetMouseCoords(ScrCenterX, ScrCenterY);
      ShowMousePointer();
    }
}



/*
   Terminate the graphics display.
*/

void TermGfx(void)
{
  if (num_colors > 0)
    {
      if (UseMouse)
        HideMousePointer();
      XUnmapWindow(x_display, x_win);
      XFreeColormap(x_display, x_cmap);
      XDestroyWindow(x_display, x_win);
      XCloseDisplay(x_display);
      x_display = NULL;
      num_colors = -1;
    }
}



/*
   Returns TRUE if DEU is in graphics mode, FALSE if it is in text mode.
*/

Bool InGfxMode(void)
{
  return (num_colors > 0);
}



/*
   Clear the screen.
*/

void ClearScreen(void)
{
  XClearWindow(x_display, x_win);
}



/*
   Set the line drawing mode: normal or XOR.
*/

void SetLineDrawingMode(int mode)
{
  XGCValues xgcv;

  switch (mode)
    {
    case DRAW_NORMAL:
      xgcv.function = GXcopy;
      break;
    case DRAW_XOR:
      xgcv.function = GXxor;
      break;
    default:
      ProgError("BUG: Invalid line drawing mode: %d", mode);
      break;
    }
  XChangeGC(x_display, x_gc, GCFunction, &xgcv);
}



/*
   Set the line style: width and pattern (solid, dotted, dashed).
*/

void SetLinePatternAndWidth(int pattern, int width)
{
  XGCValues xgcv;
 
  if (width != 1 && width != 3)
    ProgError("BUG: Invalid line width: %d", width);
  xgcv.line_width = width;
  switch (pattern)
    {
    case SOLID_PATTERN:
      xgcv.line_style = LineSolid;
      break;
    case DOTTED_PATTERN:
      xgcv.line_style = LineDoubleDash;
      break;
    case DASHED_PATTERN:
      xgcv.line_style = LineOnOffDash;
      break;
    default:
      ProgError("BUG: Invalid line pattern: %d", pattern);
      break;
    }
  XChangeGC(x_display, x_gc, GCLineWidth | GCLineStyle, &xgcv);
}


/*
   Draw a line on the screen from map coords.
*/

void DrawMapLine(Int16 mapXstart, Int16 mapYstart, Int16 mapXend, Int16 mapYend)
{
  XDrawLine(x_display, x_win, x_gc,
	    SCREENX(mapXstart), SCREENY(mapYstart),
	    SCREENX(mapXend), SCREENY(mapYend));
}



/*
   Draw a circle on the screen from map coords.
*/

void DrawMapCircle(Int16 mapXcenter, Int16 mapYcenter, Int16 mapRadius)
{
  int r = (int)(mapRadius * Scale);

  XDrawArc(x_display, x_win, x_gc,
	   (int)SCREENX(mapXcenter) - r, (int)SCREENY(mapYcenter) - r,
	   (unsigned int) (r * 2), (unsigned int) (r * 2),
	   0, 360 * 64);
}



/*
   Draw an arrow on the screen from map coords.
*/

void DrawMapVector(Int16 mapXstart, Int16 mapYstart, Int16 mapXend, Int16 mapYend)
{
  Int16  scrXstart = SCREENX(mapXstart);
  Int16  scrYstart = SCREENY(mapYstart);
  Int16  scrXend   = SCREENX(mapXend);
  Int16  scrYend   = SCREENY(mapYend);
  double r         = hypot((double) (scrXstart - scrXend),
                           (double) (scrYstart - scrYend));
  Int16  scrXoff   = (r >= 1.0) ? (Int16) ((scrXstart - scrXend) * 8.0
                                           / r * Scale) : 0;
  Int16  scrYoff   = (r >= 1.0) ? (Int16) ((scrYstart - scrYend) * 8.0
                                           / r * Scale) : 0;

  XDrawLine(x_display, x_win, x_gc, scrXstart, scrYstart, scrXend, scrYend);
  scrXstart = scrXend + 2 * scrXoff;
  scrYstart = scrYend + 2 * scrYoff;
  XDrawLine(x_display, x_win, x_gc,
	    scrXstart - scrYoff, scrYstart + scrXoff, scrXend, scrYend);
  XDrawLine(x_display, x_win, x_gc,
	    scrXstart + scrYoff, scrYstart - scrXoff, scrXend, scrYend);
}



/*
   Draw an arrow on the screen from map coords and angle (0 - 65535).
*/

void DrawMapArrow(Int16 mapXstart, Int16 mapYstart, UInt16 angle)
{
  Int16  mapXend   = mapXstart + (Int16) (50 * cos(angle / 10430.37835));
  Int16  mapYend   = mapYstart + (Int16) (50 * sin(angle / 10430.37835));
  Int16  scrXstart = SCREENX(mapXstart);
  Int16  scrYstart = SCREENY(mapYstart);
  Int16  scrXend   = SCREENX(mapXend);
  Int16  scrYend   = SCREENY(mapYend);
  double r         = hypot(scrXstart - scrXend, scrYstart - scrYend);
  Int16  scrXoff   = (r >= 1.0) ? (Int16) ((scrXstart - scrXend) * 8.0
                                           / r * Scale) : 0;
  Int16  scrYoff   = (r >= 1.0) ? (Int16) ((scrYstart - scrYend) * 8.0
                                           / r * Scale) : 0;

  XDrawLine(x_display, x_win, x_gc, scrXstart, scrYstart, scrXend, scrYend);
  scrXstart = scrXend + 2 * scrXoff;
  scrYstart = scrYend + 2 * scrYoff;
  XDrawLine(x_display, x_win, x_gc,
	    scrXstart - scrYoff, scrYstart + scrXoff, scrXend, scrYend);
  XDrawLine(x_display, x_win, x_gc,
	    scrXstart + scrYoff, scrYstart - scrXoff, scrXend, scrYend);
}



/*
   Draw a pixel on the screen.
*/

void DrawScreenPixel(Int16 X, Int16 Y)
{
  XDrawPoint(x_display, x_win, x_gc, X, Y);
}



/*
   Draw a line on the screen from screen coords.
*/

void DrawScreenLine(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xend, Yend);
}



/*
   Draw a rectangle on the screen from screen coords.
*/

void DrawScreenRectangle(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  XDrawRectangle(x_display, x_win, x_gc,
		 Xstart, Ystart,
		 Xend - Xstart, Yend - Ystart);
}



/*
   Draw a filled in box on the screen from screen coords.
*/

void DrawScreenBox(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart, Ystart,
		 Xend - Xstart, Yend - Ystart);
}



/*
   Draw a filled-in 3D-box on the screen from screen coords.
*/

void DrawScreenBox3D(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  SetColor(LIGHTGRAY);
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart + 1, Ystart + 1,
		 Xend - Xstart - 2, Yend - Ystart - 2);
  SetColor(DARKGRAY);
  XDrawLine(x_display, x_win, x_gc, Xstart, Yend, Xend, Yend);
  XDrawLine(x_display, x_win, x_gc, Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(WHITE);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(WHITE);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xend, Ystart);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xstart, Yend);
  SetColor(BLACK);
}



/*
   Draw a sunken 3D-box on the screen from screen coords.
*/

void DrawScreenBoxSunken(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  SetColor(LIGHTGRAY);
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart + 1, Ystart + 1,
		 Xend - Xstart - 2, Yend - Ystart - 2);
  SetColor(WHITE);
  XDrawLine(x_display, x_win, x_gc, Xstart, Yend, Xend, Yend);
  XDrawLine(x_display, x_win, x_gc, Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(DARKGRAY);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(DARKGRAY);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xend, Ystart);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xstart, Yend);
  SetColor(WHITE);
}



/*
   Draw a hollow 3D-box on the screen from screen coords.
*/

void DrawScreenBoxHollow(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  SetColor(BLACK);
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart + 1, Ystart + 1,
		 Xend - Xstart - 2, Yend - Ystart - 2);
  SetColor(WHITE);
  XDrawLine(x_display, x_win, x_gc, Xstart, Yend, Xend, Yend);
  XDrawLine(x_display, x_win, x_gc, Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(DARKGRAY);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      XDrawLine(x_display, x_win, x_gc,
		Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(DARKGRAY);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xend, Ystart);
  XDrawLine(x_display, x_win, x_gc, Xstart, Ystart, Xstart, Yend);
  SetColor(WHITE);
}



/*
   Draw a meter bar on the screen from screen coords (in a hollow box); max. value = 1.0
*/

void DrawScreenMeter(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend, float value)
{
  if (value < 0.0)
    value = 0.0;
  if (value > 1.0)
    value = 1.0;
  SetColor(BLACK);
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart + 1 + (Int16) ((Xend - Xstart - 2) * value),
		 Ystart + 1,
		 Xend - Xstart - (Int16) ((Xend - Xstart - 2) * value) - 2,
		 Yend - Ystart - 2);
  SetColor(LIGHTGREEN);
  XFillRectangle(x_display, x_win, x_gc,
		 Xstart + 1,
		 Ystart + 1,
		 (Int16) ((Xend - Xstart - 2) * value),
		 Yend - Ystart - 2);
}



/*
   Write text to the screen.
*/

void DrawScreenText(Int16 Xstart, Int16 Ystart, char *msg, ...)
{
  static Int16 lastX;
  static Int16 lastY;
  char temp[120];
  va_list args;

  va_start(args, msg);
  vsprintf(temp, msg, args);
  va_end(args);
  if (Xstart < 0)
    Xstart = lastX;
  if (Ystart < 0)
    Ystart = lastY;
  XDrawString(x_display, x_win, x_gc, Xstart, Ystart + 7,
	      temp, strlen(temp));
  lastX = Xstart;
  lastY = Ystart + 10;  /* or textheight("W") ? */
}



/*
   Draw a bitmap on the screen (from data in "flat" format).
*/

void DrawScreenBitmap(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend, UInt8 far *pixels)
{
  Int16 i, j;

  if (num_colors == 256)
    {
      /*! this is very slow and has to be optimized later (use an XImage?) */
      for (i = Ystart; i <= Yend; i++)
        for (j = Xstart; j <= Xend; j++)
          {
	    XSetForeground(x_display, x_gc, (unsigned long)*pixels);
	    XDrawPoint(x_display, x_win, x_gc, j, i);
            pixels++;
          }
    }
  else
    {
      for (i = Ystart; i <= Yend; i++)
        for (j = Xstart; j <= Xend; j++)
          {
	    XSetForeground(x_display, x_gc,
			   (unsigned long) TranslateTo16Color(*pixels));
	    XDrawPoint(x_display, x_win, x_gc, j, i);
            pixels++;
          }
    }
}



/*
   Draw (or erase) the pointer if we aren't using the mouse.
*/

void DrawPointer(Bool rulers)
{
  UInt16 r;

  /* use XOR mode : drawing the pointer twice erases it */
  SetLineDrawingMode(DRAW_XOR);
  /* draw the pointer */
  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  if (rulers)
    {
      SetColor(MAGENTA);
      r = (UInt16) (512 * Scale);
      XDrawArc(x_display, x_win, x_gc,
	       (int) (PointerX - r), (int) (PointerY - r),
	       (unsigned int) (r * 2), (unsigned int) (r * 2),
	       0, 360 * 64);
      r >>= 1;
      XDrawArc(x_display, x_win, x_gc,
	       (int) (PointerX - r), (int) (PointerY - r),
	       (unsigned int) (r * 2), (unsigned int) (r * 2),
	       0, 360 * 64);
      r >>= 1;
      XDrawArc(x_display, x_win, x_gc,
	       (int) (PointerX - r), (int) (PointerY - r),
	       (unsigned int) (r * 2), (unsigned int) (r * 2),
	       0, 360 * 64);
      r >>= 1;
      XDrawArc(x_display, x_win, x_gc,
	       (int) (PointerX - r), (int) (PointerY - r),
	       (unsigned int) (r * 2), (unsigned int) (r * 2),
	       0, 360 * 64);
      r = (UInt16) (1024 * Scale);
      XDrawLine(x_display, x_win, x_gc,
		PointerX - r, PointerY, PointerX + r, PointerY);
      XDrawLine(x_display, x_win, x_gc,
		PointerX, PointerY - r, PointerX, PointerY + r);
    }
  else
    {
      SetColor(YELLOW);
      XDrawLine(x_display, x_win, x_gc,
		PointerX - 15, PointerY - 13, PointerX + 15, PointerY + 13);
      XDrawLine(x_display, x_win, x_gc,
		PointerX - 15, PointerY + 13, PointerX + 15, PointerY - 13);
    }
   /* restore normal write mode */
  SetLineDrawingMode(DRAW_NORMAL);
}



/*
   Load one "playpal" palette and change all palette colours.
*/

void SetDoomPalette(int playpalnum)
{
  MDirPtr     dir;
  UInt8 huge *dpal;
  int         n;
  XColor      xcolor;

  if (playpalnum < 0 && playpalnum > 13)
    return;
  dir = FindMasterDir(MasterDir, "PLAYPAL");
  if (dir)
    {
      dpal = (UInt8 huge *)GetFarMemory(768 * sizeof(UInt8));
      BasicWadSeek(dir->wadfile, dir->dir.start);
      for (n = 0; n <= playpalnum; n++)
        BasicWadRead(dir->wadfile, dpal, 768L);

      /* gamma correction */
      if (Config.gamma > 0 && Config.gamma <= 4)
        {
          float gmult[5] = {1.0, 0.75, 0.55, 0.4, 0.3};

          for (n = 0; n < 768; n++)
            dpal[n] = (UInt8) (pow(((double) dpal[n] / 255.0), gmult[Config.gamma])
                               * 255.0);
        }

      if (Config.forceWhite == TRUE)
        {
          dpal[3 * WHITE] = 255;
          dpal[3 * WHITE + 1] = 255;
          dpal[3 * WHITE + 2] = 255;
        }

      xcolor.flags = DoRed | DoGreen | DoBlue;
      for (n = 0; n < 256; n++)
	{
	  xcolor.pixel = n;
	  xcolor.red   = (dpal[3 * n]) << 8;
	  xcolor.green = (dpal[3 * n + 1]) << 8;
	  xcolor.blue  = (dpal[3 * n + 2]) << 8;
	  XStoreColor(x_display, x_cmap, &xcolor);
	}
      FreeFarMemory(dpal);
    }
}



/*
   Set the current drawing color (from one of the 16 color constants).
*/

void SetColor(int color16)
{
  if (num_colors >= 256)
    color16 = TranslateToDoomColor(color16);
  XSetForeground(x_display, x_gc, (unsigned long) color16);
  /* update the global variable */
  current_color = color16;
}



/*
   Set the current drawing color (from Doom palette #0).
*/

void SetDoomColor(int color256)
{
  if (num_colors < 256)
    color256 = TranslateTo16Color(color256);
  XSetForeground(x_display, x_gc, (unsigned long) color256);
  /* update the global variable */
  current_color = color256;
}


static UInt16 altkeys[26] = {
    0x1e00, 0x3000, 0x2e00, 0x2000, 0x1200, 0x2100, 0x2200, 0x2300,
    0x1700, 0x2400, 0x2500, 0x2600, 0x3200, 0x3100, 0x1800, 0x1900,
    0x1000, 0x1300, 0x1f00, 0x1400, 0x1600, 0x2f00, 0x1100, 0x2d00,
    0x1500, 0x2c00
};


/*
   Wait for a key.
*/

UInt16 WaitForKey(void)
{
  int        count;
  int        add;
  XKeyEvent *xkev;
  char       buf[10];
  KeySym     ks;

  do
    {
      XWindowEvent(x_display, x_win, x_inputeventmask, &(x_xev));
      switch (x_xev.type)
	{
	case ButtonRelease:
fprintf(stderr, "BUTTON PRESS\n");  /*!!!!!!*/
	  x_buttons = 0;
	  x_modifiers = x_xev.xbutton.state;
	  break;
	case ButtonPress:
fprintf(stderr, "BUTTON RELEASE\n");  /*!!!!!!*/
	  x_buttons = x_xev.xbutton.button;
	  x_modifiers = x_xev.xbutton.state;
	  break;
	case MotionNotify:
	  x_pointerx = x_xev.xmotion.x;
	  x_pointery = x_xev.xmotion.y;
	  x_modifiers = x_xev.xmotion.state;
	  break;
	case Expose:
fprintf(stderr, "EXPOSE AND REDRAW !!!!\n");  /*!!!!!!*/
	  UpdateWindowSize();
	  return MAGIC_REDRAW_KEY;
	case KeyPress:
fprintf(stderr, "READ KEYPRESS\n"); /*!!!!!!*/
	  count = XLookupString(&x_xev.xkey, buf, 10, &ks, 0);
	  buf[count] = 0;
	  /*! memcpy(&xkev, &x_xev.xkey, sizeof(XKeyEvent)); */
	  x_modifiers = x_xev.xkey.state;
	  xkev = &x_xev.xkey;
	  if (xkev->state & Mod1Mask)
	    {
	      if (ks >= XK_a && ks <= XK_z)
		{
		  return altkeys[ks - XK_a];
		}
	      if (ks >= XK_A && ks <= XK_Z)
		{
		  return altkeys[ks - XK_A];
		}
	    }
	  switch (ks)
	    {
	    case XK_Tab:
	      if (xkev->state & ShiftMask)
		return 0x0F00;
	      else
		return 0x0009;
	    case XK_Escape:
	      return 27;
	    case XK_BackSpace:
	      return 8;
	    case XK_Return:
	    case XK_KP_Enter:
	      return 13;
	    case XK_Up:
	    case XK_KP_Up:
	      return 0x4800;
	    case XK_Down:
	    case XK_KP_Down:
	      return 0x5000;
	    case XK_Left:
	    case XK_KP_Left:
	      return 0x4b00;
	    case XK_Right:
	    case XK_KP_Right:
	      return 0x4d00;
	    case XK_Home:
	    case XK_KP_Home:
	    case XK_F27:
	      return 0x4700;
	    case XK_Page_Up:
	    case XK_KP_Page_Up:
	    case XK_F29:
	      return 0x4900;
	    case XK_Page_Down:
	    case XK_KP_Page_Down:
	    case XK_F35:
	      return 0x5100;
	    case XK_End:
	    case XK_KP_End:
	    case XK_F33:
	      return 0x4f00;
	    case XK_Insert:
	    case XK_KP_Insert:
	      return 0x5200;
	    case XK_Delete:
	    case XK_KP_Delete:
	      return 0x5300;
	    case XK_F1:
	    case XK_F2:
	    case XK_F3:
	    case XK_F4:
	    case XK_F5:
	    case XK_F6:
	    case XK_F7:
	    case XK_F8:
	    case XK_F9:
	    case XK_F10:
	    case XK_F11:
	      add = 0;
	      if (xkev->state & ShiftMask)
		{
		  add += 0x54 - 0x3b;
		}
	      if (xkev->state & ControlMask)
		{
		  add += 0x5e - 0x3b;
		}
	      if (xkev->state & Mod1Mask)
		{
		  add += 0x68 - 0x3b;
		}
	      return 0x13b + (ks - XK_F1) + add;
	    }
	  if (count == 1)
	    return buf[0];
	  break;
	}
    } while (x_xev.type != KeyPress);
  /* normally, we won't get here, but who knows? */
  return buf[0];
}


/*
   Test is a key has been pressed (non-blocking).
*/

Bool IsKeyPressed(void)
{
  if (!XCheckWindowEvent(x_display, x_win, KeyPressMask, &(x_xev)))
    {
      if (!XCheckWindowEvent(x_display, x_win, x_inputeventmask, &(x_xev)))
	return 0;
    }
  switch(x_xev.type)
    {
    case ButtonRelease:
      x_buttons = 0;
      break;
    case ButtonPress:
      x_buttons = x_xev.xbutton.button;
      break;
    case MotionNotify:
      x_pointerx = x_xev.xmotion.x;
      x_pointery = x_xev.xmotion.y;
      break;
    case KeyPress:
fprintf(stderr, "KEY PRESSED...\n"); /*!!!!!!!*/
      XPutBackEvent(x_display, &(x_xev));
      return 1;
    case Expose:
fprintf(stderr, "EXPOSE...\n");  /*!!!!!!!*/
      XPutBackEvent(x_display, &(x_xev));
      return 1;
    }
  return 0;
}


/*
   Get the status of the modifiers: Shift, Alt, Ctrl,... (non-blocking).
*/

UInt16 GetAltKeys(void)
{
  UInt16 altkey;

  altkey = 0;
  if (x_modifiers & ShiftMask)
    altkey |= 0x02;
  if (x_modifiers & ControlMask)
    altkey |= 0x04;
  if (x_modifiers & Mod1Mask)
    altkey |= 0x08;
  return altkey;
}


/* end of file */
