#include <stdio.h>

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

#include "atari.h"
#include "colours.h"

#define	FALSE	0
#define	TRUE	1

typedef enum
{
  Small,
  Large,
  Huge
} WindowSize;

static WindowSize windowsize = Large;

static Display	*display;
static Screen	*screen;
static Window	window;
static Pixmap	pixmap;
static Visual	*visual;

static GC	gc;
static GC	gc_colour[256];

static XComposeStatus	keyboard_status;

static int	SHIFT = 0x00;
static int	CONTROL = 0x00;
static UBYTE	*image_data;
static int	modified;

static int	last_colour = -1;

#define	NPOINTS	(4096/4)
#define	NRECTS	(4096/4)

static int	nrects = 0;
static int	npoints = 0;

static XPoint		points[NPOINTS];
static XRectangle	rectangles[NRECTS];

typedef enum
{
  Joystick,
  Paddle
} ControllerType;

static ControllerType controller = Joystick;
static int consol;

void Atari_Initialise (int *argc, char *argv[])
{
  XSetWindowAttributes	xswda;

  XGCValues	xgcvl;

  int	colours[256];
  int	depth;
  int	i, j;

  for (i=j=1;i<*argc;i++)
    {
      if (strcmp(argv[i],"-small") == 0)
	windowsize = Small;
      else if (strcmp(argv[i],"-large") == 0)
	windowsize = Large;
      else if (strcmp(argv[i],"-huge") == 0)
	windowsize = Huge;
      else
	argv[j++] = argv[i];
    }

  *argc = j;

  display = XOpenDisplay (NULL);
  if (!display)
    {
      printf ("Failed to open display\n");
      exit (1);
    }

  screen = XDefaultScreenOfDisplay (display);
  if (!screen)
    {
      printf ("Unable to get screen\n");
      exit (1);
    }

  depth = XDefaultDepthOfScreen (screen);

  xswda.event_mask = KeyPressMask | KeyReleaseMask | ExposureMask;

  switch (windowsize)
    {
    case Small :
      window = XCreateWindow (display,
			      XRootWindowOfScreen(screen),
			      50, 50,
			      ATARI_WIDTH, ATARI_HEIGHT, 3, depth,
			      InputOutput, visual,
			      CWEventMask | CWBackPixel,
			      &xswda);
      pixmap = XCreatePixmap (display, window,
			      ATARI_WIDTH, ATARI_HEIGHT, depth);
      break;
    case Large :
      window = XCreateWindow (display,
			      XRootWindowOfScreen(screen),
			      50, 50,
			      ATARI_WIDTH*2, ATARI_HEIGHT*2, 3, depth,
			      InputOutput, visual,
			      CWEventMask | CWBackPixel,
			      &xswda);
      pixmap = XCreatePixmap (display, window,
			      ATARI_WIDTH*2, ATARI_HEIGHT*2, depth);
      break;
    case Huge :
      window = XCreateWindow (display,
			      XRootWindowOfScreen(screen),
			      50, 50,
			      ATARI_WIDTH*3, ATARI_HEIGHT*3, 3, depth,
			      InputOutput, visual,
			      CWEventMask | CWBackPixel,
			      &xswda);
      pixmap = XCreatePixmap (display, window,
			      ATARI_WIDTH*3, ATARI_HEIGHT*3, depth);
      break;
    }
  
  XStoreName (display, window, ATARI_TITLE);

  for (i=0;i<256;i+=2)
    {
      XColor	colour;

      int	rgb = colortable[i];
      int	status;

      colour.red = (rgb & 0x00ff0000) >> 8;
      colour.green = (rgb & 0x0000ff00);
      colour.blue = (rgb & 0x000000ff) << 8;

      status = XAllocColor (display,
			    XDefaultColormapOfScreen(screen),
			    &colour);

      colours[i] = colour.pixel;
      colours[i+1] = colour.pixel;
    }

  for (i=0;i<256;i++)
    {
      xgcvl.background = colours[0];
      xgcvl.foreground = colours[i];

      gc_colour[i] = XCreateGC (display, window,
				GCForeground | GCBackground,
				&xgcvl);
    }

  xgcvl.background = colours[0];
  xgcvl.foreground = colours[0];

  gc = XCreateGC (display, window,
		  GCForeground | GCBackground,
		  &xgcvl);

  switch (windowsize)
    {
    case Small :
      XFillRectangle (display, pixmap, gc, 0, 0,
		      ATARI_WIDTH, ATARI_HEIGHT);
      break;
    case Large :
      XFillRectangle (display, pixmap, gc, 0, 0,
		      ATARI_WIDTH*2, ATARI_HEIGHT*2);
      break;
    case Huge :
      XFillRectangle (display, pixmap, gc, 0, 0,
		      ATARI_WIDTH*3, ATARI_HEIGHT*3);
      break;
    }

  XMapWindow (display, window);

  XSync (display, False);
/*
   ============================
   Storage for Atari 800 Screen
   ============================
*/
  image_data = (UBYTE*) malloc (ATARI_WIDTH * ATARI_HEIGHT);
  if (!image_data)
    {
      printf ("Failed to allocate space for image\n");
      exit (1);
    }

  consol = 7;
}

int Atari_Exit (int run_monitor)
{
  int restart;

  if (run_monitor)
    restart = monitor();
  else
    restart = FALSE;

  if (!restart)
    {
      free (image_data);

      XSync (display, True);

      XFreePixmap (display, pixmap);
      XUnmapWindow (display, window);
      XDestroyWindow (display, window);
      XCloseDisplay (display);
    }

  return restart;
}

void Atari_ScanLine_Flush ()
{
  if (windowsize == Small)
    {
      if (npoints != 0)
	{
	  XDrawPoints (display, pixmap, gc_colour[last_colour],
		       points, npoints, CoordModeOrigin);
	  npoints = 0;
	  modified = TRUE;
	}
    }
  else
    {
      if (nrects != 0)
	{
	  XFillRectangles (display, pixmap, gc_colour[last_colour],
			   rectangles, nrects);
	  nrects = 0;
	  modified = TRUE;
	}
    }

  last_colour = -1;
}

void Atari_DisplayScreen (UBYTE *screen)
{
  UBYTE *scanline_ptr;

  int xpos;
  int ypos;

  consol = 7;
  scanline_ptr = image_data;
  modified = FALSE;

  for (ypos=0;ypos<ATARI_HEIGHT;ypos++)
    {
      for (xpos=0;xpos<ATARI_WIDTH;xpos++)
	{
	  UBYTE colour;

	  colour = *screen++;
	  if (colour != *scanline_ptr)
	    {
	      int flush = FALSE;

	      if (windowsize == Small)
		{
		  if (npoints == NPOINTS)
		    flush = TRUE;
		}
	      else
		{
		  if (nrects == NRECTS)
		    flush = TRUE;
		}

	      if (colour != last_colour)
		flush = TRUE;

	      if (flush)
		{
		  Atari_ScanLine_Flush ();
		  last_colour = colour;
		}

	      if (windowsize == Small)
		{
		  points[npoints].x = xpos;
		  points[npoints].y = ypos;
		  npoints++;
		}
	      else if (windowsize == Large)
		{
		  rectangles[nrects].x = xpos << 1;
		  rectangles[nrects].y = ypos << 1;
		  rectangles[nrects].width = 2;
		  rectangles[nrects].height = 2;
		  nrects++;
		}
	      else
		{
		  rectangles[nrects].x = xpos + xpos + xpos;
		  rectangles[nrects].y = ypos + ypos + ypos;
		  rectangles[nrects].width = 3;
		  rectangles[nrects].height = 3;
		  nrects++;
		}

	      *scanline_ptr++ = colour;
	    }
	  else
	    {
	      scanline_ptr++;
	    }
	}
    }

  Atari_ScanLine_Flush ();

  if (modified)
    {
      if (windowsize == Small)
	{
	  XCopyArea (display, pixmap, window, gc, 0, 0,
		     ATARI_WIDTH, ATARI_HEIGHT, 0, 0);
	}
      else if (windowsize == Large)
	{
	  XCopyArea (display, pixmap, window, gc, 0, 0,
		     ATARI_WIDTH*2, ATARI_HEIGHT*2, 0, 0);
	}
      else
	{
	  XCopyArea (display, pixmap, window, gc, 0, 0,
		     ATARI_WIDTH*3, ATARI_HEIGHT*3, 0, 0);
	}
    }
}

int Atari_Keyboard (void)
{
  int	keycode = AKEY_NONE;

  if (XEventsQueued (display, QueuedAfterFlush) > 0)
    {
      XEvent	event;
      KeySym	keysym;
      char	buffer[128];

      XNextEvent (display, &event);

      XLookupString ((XKeyEvent*)&event, buffer, 128,
		     &keysym, &keyboard_status);

      switch (event.type)
	{
	case Expose :
	  if (windowsize == Small)
	    {
	      XCopyArea (display, pixmap, window, gc,
			 0, 0,
			 ATARI_WIDTH, ATARI_HEIGHT,
			 0, 0);
	    }
	  else if (windowsize == Large)
	    {
	      XCopyArea (display, pixmap, window, gc,
			 0, 0,
			 ATARI_WIDTH*2, ATARI_HEIGHT*2,
			 0, 0);
	    }
	  else
	    {
	      XCopyArea (display, pixmap, window, gc,
			 0, 0,
			 ATARI_WIDTH*3, ATARI_HEIGHT*3,
			 0, 0);
	    }
	  break;
	case KeyPress :
	  switch (keysym)
	    {
	    case XK_Shift_L :
	    case XK_Shift_R :
	      SHIFT = 0x40;
	      break;
	    case XK_Control_L :
	    case XK_Control_R :
	      CONTROL = 0x80;
	      break;
	    case XK_Caps_Lock :
	      keycode = AKEY_CAPSTOGGLE;
	      break;
	    case XK_Shift_Lock :
	      break;
	    case XK_Alt_L :
	    case XK_Alt_R :
	      keycode = AKEY_ATARI;
	      break;
	    case XK_F1 :
	      keycode = AKEY_WARMSTART;
	      break;
	    case XK_F2 :
	      consol &= 0x03;
	      keycode = AKEY_NONE;
	      break;
	    case XK_F3 :
	      consol &= 0x05;
	      keycode = AKEY_NONE;
	      break;
	    case XK_F4 :
	      consol &= 0x6;
	      keycode = AKEY_NONE;
	      break;
	    case XK_F5 :
	      keycode = AKEY_COLDSTART;
	      break;
	    case XK_F6 :
	      keycode = AKEY_PIL;
	      break;
	    case XK_F7 :
	      keycode = AKEY_BREAK;
	      break;
	    case XK_F8 :
	      keycode = AKEY_DISKCHANGE;
	      break;
	    case XK_F9 :
	      keycode = AKEY_EXIT;
	      break;
	    case XK_F10 :
	      switch (controller)
		{
		case Joystick :
		  controller = Paddle;
		  break;
		case Paddle :
		default :
		  controller = Joystick;
		  break;
		}
	      keycode = AKEY_NONE;
	      break;
	    case XK_Home :
	      keycode = 0x76;
	      break;
	    case XK_Insert :
	      if (SHIFT)
		keycode = AKEY_INSERT_LINE;
	      else
		keycode = AKEY_INSERT_CHAR;
	      break;
	    case XK_Delete :
	      if (CONTROL)
		keycode = AKEY_DELETE_CHAR;
	      else if (SHIFT)
		keycode = AKEY_DELETE_LINE;
	      else
		keycode = AKEY_BACKSPACE;
	      break;
	    case XK_Left :
	      keycode = AKEY_LEFT;
	      break;
	    case XK_Up :
	      keycode = AKEY_UP;
	      break;
	    case XK_Right :
	      keycode = AKEY_RIGHT;
	      break;
	    case XK_Down :
	      keycode = AKEY_DOWN;
	      break;
	    case XK_Escape :
	      keycode = AKEY_ESCAPE;
	      break;
	    case XK_Tab :
	      if (CONTROL)
		keycode = AKEY_CLRTAB;
	      else if (SHIFT)
		keycode = AKEY_SETTAB;
	      else
		keycode = AKEY_TAB;
	      break;
	    case XK_exclam :
	      keycode = '!';
	      break;
	    case XK_quotedbl :
	      keycode = '"';
	      break;
	    case XK_numbersign :
	      keycode = '#';
	      break;
	    case XK_dollar :
	      keycode = '$';
	      break;
	    case XK_percent :
	      keycode = '%';
	      break;
	    case XK_ampersand :
	      keycode = '&';
	      break;
	    case XK_quoteright :
	      keycode = '\'';
	      break;
	    case XK_at :
	      keycode = '@';
	      break;
	    case XK_parenleft :
	      keycode = '(';
	      break;
	    case XK_parenright :
	      keycode = ')';
	      break;
	    case XK_less :
	      keycode = '<';
	      break;
	    case XK_greater :
	      keycode = '>';
	      break;
	    case XK_equal :
	      keycode = '=';
	      break;
	    case XK_question :
	      keycode = '?';
	      break;
	    case XK_minus :
	      keycode = '-';
	      break;
	    case XK_plus :
	      keycode = '+';
	      break;
	    case XK_asterisk :
	      keycode = '*';
	      break;
	    case XK_slash :
	      keycode = '/';
	      break;
	    case XK_colon :
	      keycode = ':';
	      break;
	    case XK_semicolon :
	      keycode = ';';
	      break;
	    case XK_comma :
	      keycode = ',';
	      break;
	    case XK_period :
	      keycode = '.';
	      break;
	    case XK_underscore :
	      keycode = '_';
	      break;
	    case XK_bracketleft :
	      keycode = '[';
	      break;
	    case XK_bracketright :
	      keycode = ']';
	      break;
	    case XK_asciicircum :
	      keycode = '^';
	      break;
	    case XK_backslash :
	      keycode = '\\';
	      break;
	    case XK_bar :
	      keycode = '|';
	      break;
	    case XK_space :
	      keycode = ' ';
	      break;
	    case XK_Return :
	      keycode = AKEY_RETURN;
	      break;
	    case XK_0 :
	      if (CONTROL)
		keycode = AKEY_CTRL_0;
	      else
		keycode = '0';
	      break;
	    case XK_1 :
	      if (CONTROL)
		keycode = AKEY_CTRL_1;
	      else
		keycode = '1';
	      break;
	    case XK_2 :
	      if (CONTROL)
		keycode = AKEY_CTRL_2;
	      else
		keycode = '2';
	      break;
	    case XK_3 :
	      if (CONTROL)
		keycode = AKEY_CTRL_3;
	      else
		keycode = '3';
	      break;
	    case XK_4 :
	      if (CONTROL)
		keycode = AKEY_CTRL_4;
	      else
		keycode = '4';
	      break;
	    case XK_5 :
	      if (CONTROL)
		keycode = AKEY_CTRL_5;
	      else
		keycode = '5';
	      break;
	    case XK_6 :
	      if (CONTROL)
		keycode = AKEY_CTRL_6;
	      else
		keycode = '6';
	      break;
	    case XK_7 :
	      if (CONTROL)
		keycode = AKEY_CTRL_7;
	      else
		keycode = '7';
	      break;
	    case XK_8 :
	      if (CONTROL)
		keycode = AKEY_CTRL_8;
	      else
		keycode = '8';
	      break;
	    case XK_9 :
	      if (CONTROL)
		keycode = AKEY_CTRL_9;
	      else
		keycode = '9';
	      break;
	    case XK_a :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_A;
	      else if (CONTROL)
		keycode = AKEY_CTRL_A;
	      else
		keycode = 'a';
	      break;
	    case XK_b :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_B;
	      else if (CONTROL)
		keycode = AKEY_CTRL_B;
	      else
		keycode = 'b';
	      break;
	    case XK_c :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_C;
	      else if (CONTROL)
		keycode = AKEY_CTRL_C;
	      else
		keycode = 'c';
	      break;
	    case XK_d :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_D;
	      else if (CONTROL)
		keycode = AKEY_CTRL_D;
	      else
		keycode = 'd';
	      break;
	    case XK_e :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_E;
	      else if (CONTROL)
		keycode = AKEY_CTRL_E;
	      else
		keycode = 'e';
	      break;
	    case XK_f :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_F;
	      else if (CONTROL)
		keycode = AKEY_CTRL_F;
	      else
		keycode = 'f';
	      break;
	    case XK_g :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_G;
	      else if (CONTROL)
		keycode = AKEY_CTRL_G;
	      else
		keycode = 'g';
	      break;
	    case XK_h :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_H;
	      else if (CONTROL)
		keycode = AKEY_CTRL_H;
	      else
		keycode = 'h';
	      break;
	    case XK_i :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_I;
	      else if (CONTROL)
		keycode = AKEY_CTRL_I;
	      else
		keycode = 'i';
	      break;
	    case XK_j :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_J;
	      else if (CONTROL)
		keycode = AKEY_CTRL_J;
	      else
		keycode = 'j';
	      break;
	    case XK_k :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_K;
	      else if (CONTROL)
		keycode = AKEY_CTRL_K;
	      else
		keycode = 'k';
	      break;
	    case XK_l :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_L;
	      else if (CONTROL)
		keycode = AKEY_CTRL_L;
	      else
		keycode = 'l';
	      break;
	    case XK_m :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_M;
	      else if (CONTROL)
		keycode = AKEY_CTRL_M;
	      else
		keycode = 'm';
	      break;
	    case XK_n :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_N;
	      else if (CONTROL)
		keycode = AKEY_CTRL_N;
	      else
		keycode = 'n';
	      break;
	    case XK_o :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_O;
	      else if (CONTROL)
		keycode = AKEY_CTRL_O;
	      else
		keycode = 'o';
	      break;
	    case XK_p :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_P;
	      else if (CONTROL)
		keycode = AKEY_CTRL_P;
	      else
		keycode = 'p';
	      break;
	    case XK_q :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Q;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Q;
	      else
		keycode = 'q';
	      break;
	    case XK_r :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_R;
	      else if (CONTROL)
		keycode = AKEY_CTRL_R;
	      else
		keycode = 'r';
	      break;
	    case XK_s :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_S;
	      else if (CONTROL)
		keycode = AKEY_CTRL_S;
	      else
		keycode = 's';
	      break;
	    case XK_t :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_T;
	      else if (CONTROL)
		keycode = AKEY_CTRL_T;
	      else
		keycode = 't';
	      break;
	    case XK_u :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_U;
	      else if (CONTROL)
		keycode = AKEY_CTRL_U;
	      else
		keycode = 'u';
	      break;
	    case XK_v :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_V;
	      else if (CONTROL)
		keycode = AKEY_CTRL_V;
	      else
		keycode = 'v';
	      break;
	    case XK_w :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_W;
	      else if (CONTROL)
		keycode = AKEY_CTRL_W;
	      else
		keycode = 'w';
	      break;
	    case XK_x :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_X;
	      else if (CONTROL)
		keycode = AKEY_CTRL_X;
	      else
		keycode = 'x';
	      break;
	    case XK_y :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Y;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Y;
	      else
		keycode = 'y';
	      break;
	    case XK_z :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Z;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Z;
	      else
		keycode = 'z';
	      break;
	    case XK_A :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_A;
	      else if (CONTROL)
		keycode = AKEY_CTRL_A;
	      else
		keycode = 'A';
	      break;
	    case XK_B :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_B;
	      else if (CONTROL)
		keycode = AKEY_CTRL_B;
	      else
		keycode = 'B';
	      break;
	    case XK_C :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_C;
	      else if (CONTROL)
		keycode = AKEY_CTRL_C;
	      else
		keycode = 'C';
	      break;
	    case XK_D :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_D;
	      else if (CONTROL)
		keycode = AKEY_CTRL_D;
	      else
		keycode = 'D';
	      break;
	    case XK_E :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_E;
	      else if (CONTROL)
		keycode = AKEY_CTRL_E;
	      else
		keycode = 'E';
	      break;
	    case XK_F :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_F;
	      else if (CONTROL)
		keycode = AKEY_CTRL_F;
	      else
		keycode = 'F';
	      break;
	    case XK_G :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_G;
	      else if (CONTROL)
		keycode = AKEY_CTRL_G;
	      else
		keycode = 'G';
	      break;
	    case XK_H :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_H;
	      else if (CONTROL)
		keycode = AKEY_CTRL_H;
	      else
		keycode = 'H';
	      break;
	    case XK_I :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_I;
	      else if (CONTROL)
		keycode = AKEY_CTRL_I;
	      else
		keycode = 'I';
	      break;
	    case XK_J :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_J;
	      else if (CONTROL)
		keycode = AKEY_CTRL_J;
	      else
		keycode = 'J';
	      break;
	    case XK_K :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_K;
	      else if (CONTROL)
		keycode = AKEY_CTRL_K;
	      else
		keycode = 'K';
	      break;
	    case XK_L :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_L;
	      else if (CONTROL)
		keycode = AKEY_CTRL_L;
	      else
		keycode = 'L';
	      break;
	    case XK_M :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_M;
	      else if (CONTROL)
		keycode = AKEY_CTRL_M;
	      else
		keycode = 'M';
	      break;
	    case XK_N :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_N;
	      else if (CONTROL)
		keycode = AKEY_CTRL_N;
	      else
		keycode = 'N';
	      break;
	    case XK_O :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_O;
	      else if (CONTROL)
		keycode = AKEY_CTRL_O;
	      else
		keycode = 'O';
	      break;
	    case XK_P :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_P;
	      else if (CONTROL)
		keycode = AKEY_CTRL_P;
	      else
		keycode = 'P';
	      break;
	    case XK_Q :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Q;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Q;
	      else
		keycode = 'Q';
	      break;
	    case XK_R :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_R;
	      else if (CONTROL)
		keycode = AKEY_CTRL_R;
	      else
		keycode = 'R';
	      break;
	    case XK_S :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_S;
	      else if (CONTROL)
		keycode = AKEY_CTRL_S;
	      else
		keycode = 'S';
	      break;
	    case XK_T :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_T;
	      else if (CONTROL)
		keycode = AKEY_CTRL_T;
	      else
		keycode = 'T';
	      break;
	    case XK_U :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_U;
	      else if (CONTROL)
		keycode = AKEY_CTRL_U;
	      else
		keycode = 'U';
	      break;
	    case XK_V :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_V;
	      else if (CONTROL)
		keycode = AKEY_CTRL_V;
	      else
		keycode = 'V';
	      break;
	    case XK_W :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_W;
	      else if (CONTROL)
		keycode = AKEY_CTRL_W;
	      else
		keycode = 'W';
	      break;
	    case XK_X :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_X;
	      else if (CONTROL)
		keycode = AKEY_CTRL_X;
	      else
		keycode = 'X';
	      break;
	    case XK_Y :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Y;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Y;
	      else
		keycode = 'Y';
	      break;
	    case XK_Z :
	      if (SHIFT && CONTROL)
		keycode = AKEY_SHFTCTRL_Z;
	      else if (CONTROL)
		keycode = AKEY_CTRL_Z;
	      else
		keycode = 'Z';
	      break;
	    default :
	      keycode = AKEY_NONE;
	      printf ("Pressed Keysym = %x\n", (int)keysym);
	      break;
	    }
	  break;
	case KeyRelease :
	  switch (keysym)
	    {
	    case XK_Shift_L :
	    case XK_Shift_R :
	      SHIFT = 0x00;
	      break;
	    case XK_Control_L :
	    case XK_Control_R :
	      CONTROL = 0x00;
	      break;
	    default :
	      break;
	    }
	  break;
	}
    }

  return keycode;
}

int Atari_PORT (int num)
{
  int	port = 0xff;	/* Both Central */

  if (num == 0)
    {
      Window	root_return;
      Window	child_return;
      int	root_x_return;
      int	root_y_return;
      int	win_x_return;
      int	win_y_return;
      int	mask_return;

      XQueryPointer (display, window, &root_return, &child_return,
		     &root_x_return, &root_y_return,
		     &win_x_return, &win_y_return,
		     &mask_return);

      switch (controller)
	{
	case Paddle :
	  if (mask_return)
	    port &= 0xfb;
	  break;
	case Joystick :
	  {
	    int	center_x;
	    int	center_y;
	    int	threshold;

	    if (windowsize == Small)
	      {
		center_x = ATARI_WIDTH / 2;
		center_y = ATARI_HEIGHT / 2;
		threshold = 32;
	      }
	    else if (windowsize == Large)
	      {
		center_x = (ATARI_WIDTH * 2) / 2;
		center_y = (ATARI_HEIGHT * 2) / 2;
		threshold = 64;
	      }
	    else
	      {
		center_x = (ATARI_WIDTH * 3) / 2;
		center_y = (ATARI_HEIGHT * 3) / 2;
		threshold = 96;
	      }

	    if (win_x_return < (center_x - threshold))
	      port &= 0xfb;
	    if (win_x_return > (center_x + threshold))
	      port &= 0xf7;
	    if (win_y_return < (center_y - threshold))
	      port &= 0xfe;
	    if (win_y_return > (center_y + threshold))
	      port &= 0xfd;
	  }
	  break;
	}
    }

  return port;
}

int Atari_TRIG (int num)
{
  int	trig = 1;	/* Trigger not pressed */

  if (num == 0)
    {
      Window	root_return;
      Window	child_return;
      int	root_x_return;
      int	root_y_return;
      int	win_x_return;
      int	win_y_return;
      int	mask_return;

      if (XQueryPointer (display, window, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return))
	{
	  if (mask_return) trig = 0;
	}
    }

  return trig;
}

int Atari_POT (int num)
{
  int	pot;

  if (num == 0)
    {
      Window	root_return;
      Window	child_return;
      int	root_x_return;
      int	root_y_return;
      int	win_x_return;
      int	win_y_return;
      int	mask_return;

      if (XQueryPointer (display, window, &root_return,
			 &child_return, &root_x_return, &root_y_return,
			 &win_x_return, &win_y_return, &mask_return))
	{
	  if (windowsize == Small)
	    {
	      pot = ((float)((ATARI_WIDTH) - win_x_return) /
		     (float)(ATARI_WIDTH)) * 228;
	    }
	  else if (windowsize == Large)
	    {
	      pot = ((float)((ATARI_WIDTH * 2) - win_x_return) /
		     (float)(ATARI_WIDTH * 2)) * 228;
	    }
	  else
	    {
	      pot = ((float)((ATARI_WIDTH * 3) - win_x_return) /
		     (float)(ATARI_WIDTH * 3)) * 228;
	    }
	}
    }
  else
    {
      pot = 228;
    }

  return pot;
}

int Atari_CONSOL (void)
{
  return consol;
}

int Atari_AUDC (int channel, int byte)
{
}

int Atari_AUDF (int channel, int byte)
{
}

int Atari_AUDCTL (int byte)
{
}
