/*----------------------------------------------------------------------------*
 | 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_GFXSGI.C - Graphical routines for SGI (GL)

 Most functions written by Pete Wyckoff
*/

/* the includes */
#include "deu.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <gl/gl.h>
#include <gl/device.h>
#include <fmclient.h>

/* turn off GL color predefinitions, to take DEU's. */
#undef BLACK
#undef RED
#undef GREEN
#undef YELLOW
#undef BLUE
#undef MAGENTA
#undef CYAN
#undef WHITE

#define __sgi_c

/* more includes */
#include <math.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 */


/*
   Initialise the graphics display.
*/

void InitGfx(void)
{
  int  i;
  long x, y;

  /*! prefsize(XSIZE, YSIZE); */
  prefposition(450, 450 + XSIZE - 1, 400, 400 + YSIZE - 1);
  foreground();
  (void) winopen("deu-sgi");
  /*! winconstraints(); Uncomment this to allow resizes. */
  getorigin(&x_origin, &y_origin);
  cmode();
  zbuffer(FALSE);
  gconfig();
  num_colors = 256;

  InitMouseDriver();

  fminit();
  fmsetfont(fmscalefont(fmfindfont("Clean"), FONTHEIGHT));
  for (i = BUT0; i <= MAXKBDBUT; i++)
    qdevice(i);

  /* don't queue all the extended keys, just the ones we need. */
  unqdevice(LEFTSHIFTKEY);
  unqdevice(RIGHTSHIFTKEY);
  unqdevice(LEFTCTRLKEY);
  unqdevice(CAPSLOCKKEY);
  qdevice(INSERTKEY);
  qdevice(PAGEUPKEY);
  qdevice(PAGEDOWNKEY);
  qdevice(HOMEKEY);
  qdevice(ENDKEY);
  qdevice(F1KEY);
  qdevice(F2KEY);
  qdevice(F3KEY);
  qdevice(F4KEY);
  qdevice(F5KEY);
  qdevice(F6KEY);
  qdevice(F7KEY);
  qdevice(F8KEY);
  qdevice(F9KEY);
  qdevice(F10KEY);
  /* and queue the mouse buttons */
  qdevice(LEFTMOUSE);
  qdevice(MIDDLEMOUSE);
  qdevice(RIGHTMOUSE);
  /* These make it look like a PC screen, moving the origin to top-left */
  translate(0.0, (float)YSIZE, 0.0);
  scale(1.0, -1.0, 1.0);
  color(TranslateToDoomColor(BLACK));
  clear();
  if (num_colors >= 256)
    SetDoomPalette(0);
  SetColor(WHITE);
  setlinestyle(0, 0, 1);
  settextstyle(0, 0, 1);
  getsize(&x, &y);
  ScrMaxX = (UInt16)x - 1;
  ScrMaxY = (UInt16)y - 1;
  ScrCenterX = ScrMaxX / 2;
  ScrCenterY = ScrMaxY / 2;
  if (UseMouse)
    {
      ResetMouseLimits();
      SetMouseCoords(ScrCenterX, ScrCenterY);
      ShowMousePointer();
    }
}



/*
   Terminate the graphics display.
*/

void TermGfx(void)
{
  if (num_colors > 0)
    {
      if (UseMouse)
        HideMousePointer();
      winclose(winget());
      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)
{
  color(TranslateToDoomColor(BLACK));
  clear();
  color(current_color);
}



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

void SetLineDrawingMode(int mode)
{
  switch (mode)
    {
    case DRAW_NORMAL:
      logicop(LO_SRC);
      break;
    case DRAW_XOR:
      logicop(LO_XOR);
      break;
    default:
      ProgError("BUG: Invalid line drawing mode: %d", mode);
      break;
    }
}



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

void SetLinePatternAndWidth(int pattern, int width)
{
  if (width != 1 && width != 3)
    ProgError("BUG: Invalid line width: %d", width);
  linewidth(width);
  switch (pattern)
    {
    case SOLID_PATTERN:
      /*! ??? */
      break;
    case DOTTED_PATTERN:
      /*! ??? */
      break;
    case DASHED_PATTERN:
      /*! ??? */
      break;
    default:
      ProgError("BUG: Invalid line pattern: %d", pattern);
      break;
    }
}


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

void DrawMapLine(Int16 mapXstart, Int16 mapYstart, Int16 mapXend, Int16 mapYend)
{
  short v[2];

  bgnline();
  v[0] = (short)SCREENX(mapXstart);
  v[1] = (short)SCREENY(mapYstart);
  v2s(v);
  v[0] = (short)SCREENX(mapXend);
  v[1] = (short)SCREENY(mapYend);
  v2s(v);
  endline();
}



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

void DrawMapCircle(Int16 mapXcenter, Int16 mapYcenter, Int16 mapRadius)
{
  arcs(SCREENX(mapXcenter), SCREENY(mapYcenter),
       (int) (mapRadius * Scale), 0, 3600);
}



/*
   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;

  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  DrawScreenLine(scrXstart, scrYstart, scrXend, scrYend);
  scrXstart = scrXend + 2 * scrXoff;
  scrYstart = scrYend + 2 * scrYoff;
  DrawScreenLine(scrXstart - scrYoff, scrYstart + scrXoff, scrXend, scrYend);
  DrawScreenLine(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;

  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  DrawScreenLine(scrXstart, scrYstart, scrXend, scrYend);
  scrXstart = scrXend + 2 * scrXoff;
  scrYstart = scrYend + 2 * scrYoff;
  DrawScreenLine(scrXstart - scrYoff, scrYstart + scrXoff, scrXend, scrYend);
  DrawScreenLine(scrXstart + scrYoff, scrYstart - scrXoff, scrXend, scrYend);
}



/*
   Draw a pixel on the screen.
*/

void DrawScreenPixel(Int16 X, Int16 Y)
{
  Colorindex c[1];

  c[0] = (Colorindex)current_color;
  /* rectwrite doesn't pay attention to viewing matrix */
  /*! check if Y coord is OK */
  rectwrite(X, ScrMaxY - Y + 1, X, ScrMaxY - Y + 1, c);
}



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

void DrawScreenLine(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  short v[2];

  bgnline();
  v[0] = (short)Xstart;
  v[1] = (short)Ystart;
  v2s(v);
  v[0] = (short)Xend;
  v[1] = (short)Yend;
  v2s(v);
  endline();
}



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

void DrawScreenRectangle(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  rects(Xstart, Ystart, Xend, Yend);
}



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

void DrawScreenBox(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  rectfs(Xstart, Ystart, Xend, Yend);  /* could use sboxf if too slow */
}



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

void DrawScreenBox3D(Int16 Xstart, Int16 Ystart, Int16 Xend, Int16 Yend)
{
  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  SetColor(LIGHTGRAY);
  rectfs(Xstart + 1, Ystart + 1, Xend - 1, Yend - 1);
  SetColor(DARKGRAY);
  DrawScreenLine(Xstart, Yend, Xend, Yend);
  DrawScreenLine(Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      DrawScreenLine(Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      DrawScreenLine(Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(WHITE);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(WHITE);
  DrawScreenLine(Xstart, Ystart, Xend, Ystart);
  DrawScreenLine(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)
{
  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  SetColor(LIGHTGRAY);
  rectfs(Xstart + 1, Ystart + 1, Xend - 1, Yend - 1);
  SetColor(WHITE);
  DrawScreenLine(Xstart, Yend, Xend, Yend);
  DrawScreenLine(Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      DrawScreenLine(Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      DrawScreenLine(Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(DARKGRAY);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(DARKGRAY);
  DrawScreenLine(Xstart, Ystart, Xend, Ystart);
  DrawScreenLine(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)
{
  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  SetColor(BLACK);
  rectfs(Xstart + 1, Ystart + 1, Xend - 1, Yend - 1);
  SetColor(WHITE);
  DrawScreenLine(Xstart, Yend, Xend, Yend);
  DrawScreenLine(Xend, Ystart, Xend, Yend);
  if (Xend - Xstart > 20 && Yend - Ystart > 20)
    {
      DrawScreenLine(Xstart + 1, Yend - 1, Xend - 1, Yend - 1);
      DrawScreenLine(Xend - 1, Ystart + 1, Xend - 1, Yend - 1);
      SetColor(DARKGRAY);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xstart + 1, Yend - 1);
      DrawScreenLine(Xstart + 1, Ystart + 1, Xend - 1, Ystart + 1);
    }
  SetColor(DARKGRAY);
  DrawScreenLine(Xstart, Ystart, Xend, Ystart);
  DrawScreenLine(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);
  rectfs(Xstart + 1 + (Int16) ((Xend - Xstart - 2) * value), Ystart + 1, Xend - 1, Yend - 1);
  SetColor(LIGHTGREEN);
  rectfs(Xstart + 1, Ystart + 1, Xstart + 1 + (Int16) ((Xend - Xstart - 2) * value), Yend - 1);
}



/*
   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;
  cmov2s(Xstart, Ystart + 7); /* 7 = offset for font height */
  fmprstr(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)
{
  int i;

  pixmode(PM_SIZE, 8);
  for (i = Ystart; i <= Yend; i++)
    lrectwrite(Xstart, ScrMaxY - i + 1, Xend, ScrMaxY - i + 1,
               (unsigned long *)&pixels[i * (Xend - Xstart + 1)]);
}



/*
   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 */
  logicop(LO_XOR);
  /* draw the pointer */
  /*! optimize this later: replace DrawScreenLine by direct GL funcs. */
  if (rulers)
    {
      SetColor(MAGENTA);
      r = (UInt16) (512 * Scale);
      arcs(PointerX, PointerY, r, 0, 3600);
      r >>= 1;
      arcs(PointerX, PointerY, r, 0, 3600);
      r >>= 1;
      arcs(PointerX, PointerY, r, 0, 3600);
      r >>= 1;
      arcs(PointerX, PointerY, r, 0, 3600);
      r = (UInt16) (1024 * Scale);
      DrawScreenLine(PointerX - r, PointerY, PointerX + r, PointerY);
      DrawScreenLine(PointerX, PointerY - r, PointerX, PointerY + r);
    }
  else
    {
      SetColor(YELLOW);
      DrawScreenLine(PointerX - 15, PointerY - 13, PointerX + 15, PointerY + 13);
      DrawScreenLine(PointerX - 15, PointerY + 13, PointerX + 15, PointerY - 13);
    }
   /* restore normal write mode */
  logicop(LO_SRC);
}



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

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

  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;
        }

      for (n = 0; n < 256; n++)
        mapcolor(n, dpal[3 * n], dpal[3 * n + 1], dpal[3 * n + 2]);
      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);
  color(TranslateToDoomColor(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);
  color(color256);
  /* update the global variable */
  current_color = color256;
}


/* stolen from Deu-X */
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)
{
  long   dev;
  short  val;
  UInt16 key;

  while ((dev = qread(&val)))
    {
      if (ISKEYBD(dev) && val == 0)
        continue;
      key = 0xffff;
      switch (dev)
        {
	case AKEY:
          key = 'A';
          break;
	case BKEY:
          key = 'B';
          break;
	case CKEY:
          key = 'C';
          break;
	case DKEY:
          key = 'D';
          break;
	case EKEY:
          key = 'E';
          break;
	case FKEY:
          key = 'F';
          break;
	case GKEY:
          key = 'G';
          break;
	case HKEY:
          key = 'H';
          break;
	case IKEY:
          key = 'I';
          break;
	case JKEY:
          key = 'J';
          break;
	case KKEY:
          key = 'K';
          break;
	case LKEY:
          key = 'L';
          break;
	case MKEY:
          key = 'M';
          break;
	case NKEY:
          key = 'N';
          break;
	case OKEY:
          key = 'O';
          break;
	case PKEY:
          key = 'P';
          break;
	case QKEY:
          key = 'Q';
          break;
	case RKEY:
          key = 'R';
          break;
	case SKEY:
          key = 'S';
          break;
	case TKEY:
          key = 'T';
          break;
	case UKEY:
          key = 'U';
          break;
	case VKEY:
          key = 'V';
          break;
	case WKEY:
          key = 'W';
          break;
	case XKEY:
          key = 'X';
          break;
	case YKEY:
          key = 'Y';
          break;
	case ZKEY:
          key = 'Z';
          break;
	case BACKSPACEKEY:
          key = 0x08;
          break;
	case TABKEY:
	  if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
	    key = 0x09;
	  else key = 0x0f00; /* "shift-tab" */
	  break;
	case RETKEY:
          key = 0x0d;
          break;
	case ESCKEY:
          key = 0x01b;
          break;
	case UPARROWKEY:
          key = 0x4800;
          break;
	case DOWNARROWKEY:
          key = 0x5000;
          break;
	case LEFTARROWKEY:
          key = 0x4b00;
          break;
	case RIGHTARROWKEY:
          key = 0x4d00;
          break;
	case PAGEUPKEY:
          key = 0x4900;
          break;
	case PAGEDOWNKEY:
          key = 0x5100;
          break;
	case HOMEKEY:
          key = 0x4700;
          break;
	case ENDKEY:
          key = 0x4f00;
          break;
	case F1KEY:
          key = 0x3b00;
          break;
	case F2KEY:
          key = 0x3c00;
          break;
	case F3KEY:
          key = 0x3d00;
          break;
	case F4KEY:
          key = 0x3e00;
          break;
	case F5KEY:
          key = 0x3f00;
          break;
	case F6KEY:
          key = 0x4000;
          break;
	case F7KEY:
          key = 0x4100;
          break;
	case F8KEY:
          key = 0x4200;
          break;
	case F9KEY:
          key = 0x4300;
          break;
	case F10KEY:
          key = 0x4400;
          break;
	case SPACEKEY:
          key = ' ';
          break;
	case ONEKEY:
          key = '1';
          break;
	case TWOKEY:
          key = '2';
          break;
	case THREEKEY:
          key = '3';
          break;
	case FOURKEY:
          key = '4';
          break;
	case FIVEKEY:
          key = '5';
          break;
	case SIXKEY:
          key = '6';
          break;
	case SEVENKEY:
          key = '7';
          break;
	case EIGHTKEY:
          key = '8';
          break;
	case NINEKEY:
          key = '9';
          break;
	case ZEROKEY:
          key = '0';
          break;
	case INSERTKEY:
          key = 0x5200;
          break;
	case DELKEY:
          key = 0x5300;
          break;
	case EQUALKEY:
          key = '=';
          break;
	case MINUSKEY:
          key = '-';
          break;
	case PERIODKEY:
	  if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
	    key = '>';
	  break;
	case COMMAKEY:
	  if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
	    key = '<';
	  break;
	/* mouse changed */
	case LEFTMOUSE:
	case MIDDLEMOUSE:
	case RIGHTMOUSE:
	case MOUSEX:
	case MOUSEY:
          /*! check if there is a nicer way to do that */
          key = 0;  /* just return zero */
          break;
	/* maintainence stuff */
	case INPUTCHANGE:
          continue;  /* ignore */
	case REDRAW:
          /*! this debug message should be removed! */
	  printf("Redrawing.\n");
	  key = MAGIC_REDRAW_KEY;
          getorigin(&x_origin, &y_origin);
	  break;
	default:
          printf("SGI device unknown: %ld\n", dev);
	  continue;
        }
      /* Change the value if ALT is pressed with a letter. */
      if ((key >= 'A' || key <= 'Z')
          && (getbutton(LEFTALTKEY) || getbutton(RIGHTALTKEY)))
	key = altkeys[key - 'A'];
      if ((key == '3')
          && (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY)))
	key = '#';
      if ((key >= '0' && key <= '9')
          && (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY)))
	key = 0xffff;  /* to distinguish '#' */

      /*
      if (key != 0)
	  printf("key %d down == 0x%04x = '%c'\n", dev, key, key); */
      return key;
    }
}


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

Bool IsKeyPressed(void)
{
  long   dev;
  short  val;

  dev = qtest();
  if (ISKEYBD(dev))
    {  /* must not report key-up */
      (void) qread(&val);
      if (val == 0)
	dev = qtest();
      else
	qenter(dev, val);
    }
  if (dev != 0)
    return TRUE;
  else
    return FALSE;
}


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

UInt16 GetAltKeys(void)
{
  UInt16 altkey;

  /* Seems only these are needed:
       L/R shift in 0x03,
       Alt in 0x08,
       Scroll-lock in 0x10.
  */
  altkey = 0;
  if (getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY))
    altkey |= 0x03;
  if (getbutton(LEFTALTKEY) || getbutton(RIGHTALTKEY))
    altkey |= 0x08;
  if (getbutton(CAPSLOCKKEY)) /*! Why CAPS?  No Scroll Lock on SGI keyboards? */
    altkey |= 0x10;
  return altkey;
}


/* end of file */
