/* 
   PXKEventFactory.m

   Copyright (C) 1996 Free Software Foundation, Inc.

   Author:  Pascal Forget <pascal@wsc.com>
   Date: March 1996
   
   This file is part of the GNUstep GUI X/DPS Backend.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   If you are interested in a warranty or support for this source code,
   contact Scott Christley <scottc@net-community.com> for more information.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ 

#include <AppKit/AppKit.h>
#include <gnustep/xdps/PXKEventFactory.h>
#include <gnustep/xdps/PXKWindow.h>

extern NSEvent *NullEvent;

/*
 * Private functions (function calls are faster than method calls)
 */
NSEvent *
process_key_down(XEvent *xEvent);

NSEvent *
process_key_up(XEvent *xEvent);

NSEvent *
process_mouse_down(XEvent *xEvent);

NSEvent *
process_mouse_moved(XEvent *xEvent);

NSEvent *
process_mouse_up(XEvent *xEvent);

unsigned short
process_key_code(XEvent *xEvent, KeySym keysym,
		 unsigned int eventModifierFlags);

unsigned int
process_modifier_flags(unsigned int state);

/* Get the next X/Windows event and translate to a NSEvent */
NSEvent *
nextEvent(void)
{
  XEvent xEvent;
  NSRect new_frame;
  NSEvent *e;
  NSWindow *w = nil;

  NSLog(@"Get next XWindows event\n");
  e = NullEvent;
  XNextEvent(pxkDisplay, &xEvent);

  switch  (xEvent.type) {

    /* mouse button events */
  case ButtonPress:
    e = process_mouse_down(&xEvent);
    break;
  case ButtonRelease:
    e = process_mouse_up(&xEvent);
    break;

    /* change to stacking order */
  case CirculateNotify:
    NSLog(@"CirculateNotify\n");
    break;
  case CirculateRequest:
    NSLog(@"CirculateRequest\n");
    break;

    /* client events */
  case ClientMessage:
    NSLog(@"ClientMessage\n");
    break;

    /* colormap attribute changes */
  case ColormapNotify:
    NSLog(@"ColormapNotify\n");
    break;

    /* window has been resized, change width and
     * height to send to draw_text and draw_graphics
     * in next Expose */
  case ConfigureNotify:
    NSLog(@"ConfigureNotify\n");
    new_frame.origin.x = (float)xEvent.xconfigure.x;
    new_frame.origin.y = (float)xEvent.xconfigure.y;
    new_frame.size.width = (float)xEvent.xconfigure.width;
    new_frame.size.height = (float)xEvent.xconfigure.height; 
    NSLog(@"New frame %f %f %f %f\n", new_frame.origin.x, new_frame.origin.y,
	  new_frame.size.width, new_frame.size.height);
    NSLog(@"border_width %d\n", xEvent.xconfigure.border_width);
    w = nswindow_for_xwindow(xEvent.xconfigure.window);
    [(PXKWindow *)w setFrameFromXFrame: new_frame];
    break;

    /* same as ConfigureNotify but we get this event before
       the change has actually occurred. */
  case ConfigureRequest:
    NSLog(@"ConfigureRequest\n");
    break;

    /* a window has been created */
  case CreateNotify:
    NSLog(@"CreateNotify\n");
    break;

    /* a window has been destroyed */
  case DestroyNotify:
    NSLog(@"DestroyNotify\n");
    break;

    /* when the pointer enters a window */
  case EnterNotify:
    NSLog(@"EnterNotify\n");
    break;

    /* when the pointer leaves a window */
  case LeaveNotify:
    NSLog(@"LeaveNotify\n");
    break;

    /* portion of window becomes visible and we must redisplay */
  case Expose:
    {
      NSWindow *wind;
      NSView *cv;

      NSLog(@"Expose\n");

      /* find the NSWindow */
      wind = nswindow_for_xwindow(xEvent.xexpose.window);
      cv = [wind contentView];

      /* stupid implementation for now until we start keeping
	 track of invalidated regions */
      [cv display];

      break;
    }

    /* keyboard focus enters a window */
  case FocusIn:
    NSLog(@"FocusIn\n");
    break;

    /* keyboard focus leaves a window */
  case FocusOut:
    NSLog(@"FocusOut\n");
    break;

  case GraphicsExpose:
    NSLog(@"GraphicsExpose\n");
    break;

  case NoExpose:
    NSLog(@"NoExpose\n");
    break;

    /* a window is moved because of change in the size of its parent */
  case GravityNotify:
    NSLog(@"GravityNotify\n");
    break;

    /* a key has been pressed */
  case KeyPress:
    e = process_key_down(&xEvent);
    //	XRefreshKeyboardMapping(&xEvent);
    break;
	
    /* a key has been released */
  case KeyRelease:
    e = process_key_up(&xEvent);
    break;

    /* reports state of keyboard when pointer or focus enters a window */
  case KeymapNotify:
    NSLog(@"KeymapNotify\n");
    break;

    /* when a window changes stage from ummapped to mapped or vice versa */
  case MapNotify:
    NSLog(@"MapNotify\n");
    break;
  case UnmapNotify:
    NSLog(@"UnmapNotify\n");
    break;

    /* like MapNotify but before the request is carried out */
  case MapRequest:
    NSLog(@"MapRequest\n");
    break;

    /* when the mappings for keyboard or mouse has been
       change by another client */
  case MappingNotify:
    NSLog(@"MappingNotify\n");
    //	XRefreshKeyboardMapping(&xEvent);
    break;

    /* the mouse has moved */
  case MotionNotify:
    NSLog(@"MotionNotify\n");
    e = process_mouse_moved(&xEvent);
    break;
	
    /* a property of a window has changed or been deleted */
  case PropertyNotify:
    NSLog(@"PropertyNotify\n");
    break;
	
    /* a client successfully reparents a window */
  case ReparentNotify:
    NSLog(@"ReparentNotify\n");
    NSLog(@"parent offset %f %f\n", xEvent.xreparent.x,
	  xEvent.xreparent.y);
    break;

    /* another client attempts to change the size of a window */
  case ResizeRequest:
    NSLog(@"ResizeRequest\n");
    break;

    /* events dealing with the selection */
  case SelectionClear:
  case SelectionNotify:
  case SelectionRequest:
    NSLog(@"Selection*\n");
    break;

    /* a change in the visibility of a window has occurred */
  case VisibilityNotify:
    NSLog(@"VisibilityNotify\n");
    break;

    /* We shouldn't get here unless we forgot to trap an
       event above. */
  default:
    NSLog(@"Received an untrapped event\n");
    break;
	
  } /* end event type switch */    

  return e;
}

/*
 * implementation of the private functions
 *
 * I've tried to create as few variables as possible
 * in the following functions as they are called over
 * and over again.
 *
 * The following functions are not part of OpenStep.
 * They are used to convert X events into NSEvents.
 *
 * - Pascal Forget <pascal@wsc.com>
 */

NSEvent *
process_mouse_down(XEvent *xEvent)
{
  XEvent event0, event1, event2;
  int clickCount = 1;
  NSEventType eventType;
  NSPoint eventLocation;
  unsigned int eventFlags;
  NSEvent *e;
  NSWindow *w;
  NSRect r;

  Display *display = xDisplay();

  NSLog(@"Process mouseDown\n");

  eventFlags = process_modifier_flags(xEvent->xbutton.state);
    
  if (xEvent->xbutton.button == Button1) {
    NSLog(@"Got a NSLeftMouseDown\n");
    eventType = NSLeftMouseDown;
  } else {
    NSLog(@"Got a NSRightMouseDown\n");
    eventType = NSRightMouseDown;
  }

  // construct location in window
  // need to flip coordinates to be in postscript coordinates
  w = nswindow_for_xwindow(xEvent->xbutton.window);
  r = [w frame];
  eventLocation.x = xEvent->xbutton.x;
  eventLocation.y = r.size.height - xEvent->xbutton.y;

#if 0
  while(1) {
    /* Get rid of presses on other buttons */
    while(XCheckTypedEvent(display, ButtonPress, &event0)){};
	
	/* Wait for release; if on correct button, exit */ 
    XCheckMaskEvent(display, ButtonReleaseMask, &event0);

    if (event0.xbutton.button == xEvent.xbutton.button)
      {
	break;
      }
  }

  /* Wait 0.1s, leaving time for the other events to arrive */
  usleep(10000); 

  /*
     * Now check if the same button has been pressed again.
     * If so, we consider the whole mouse-up-down-up sequence
     * as a single event, namely a Left mouseDown double-click.
     */

  if (XPending(display)>1) {
    XNextEvent(display, &event1);
    XNextEvent(display, &event2);

    if ((event1.type == ButtonPress) &&
	(event1.xbutton.button == xEvent->xbutton.button) &&
	(event2.type == ButtonRelease) &&
	(event2.xbutton.button == xEvent->xbutton.button))
      {
	clickCount = 2;
	XPutBackEvent(display, &event2);
      } else {
	XPutBackEvent(display, &event2);
	XPutBackEvent(display, &event1);
	XPutBackEvent(display, &event0);
      }
  }
#endif

  e = [NSEvent mouseEventWithType:eventType
	       location:eventLocation
	       modifierFlags:eventFlags
	       timestamp:(NSTimeInterval)xEvent->xbutton.time
	       windowNumber:[w windowNumber]
	       context:nil
	       eventNumber:xEvent->xbutton.serial
	       clickCount:clickCount
	       pressure:1.0];

  return e;
}

/*
 * The process_mouse_moved function generates a mouseEvent.
 * It either sends a mouseMoved or a mouseDragged message
 * to the key window, depending if a button was depressed
 * while the mouse moved.
 */

NSEvent *
process_mouse_moved(XEvent *xEvent)
{
  NSPoint eventLocation;
  unsigned int eventFlags;
  NSEvent *e;
  NSWindow *w;
  NSRect r;

  NSLog(@"Process mouseMoved\n");

  eventFlags = process_modifier_flags(xEvent->xbutton.state);
    
  // construct location in window
  // need to flip coordinates to be in postscript coordinates
  w = nswindow_for_xwindow(xEvent->xbutton.window);
  r = [w frame];
  eventLocation.x = xEvent->xbutton.x;
  eventLocation.y = r.size.height - xEvent->xbutton.y;
    
  if (xEvent->xbutton.button == Button1) {

    e = [NSEvent mouseEventWithType:NSLeftMouseDragged
		 location:eventLocation
		 modifierFlags:eventFlags
		 timestamp:(NSTimeInterval)xEvent->xmotion.time
		 windowNumber:[w windowNumber]
		 context:nil
		 eventNumber:xEvent->xmotion.serial
		 clickCount:1
		 pressure:1.0];
	
  } else if (xEvent->xbutton.button == Button2) {

    e = [NSEvent mouseEventWithType:NSRightMouseDragged
		 location:eventLocation
		 modifierFlags:eventFlags
		 timestamp:(NSTimeInterval)xEvent->xbutton.time
		 windowNumber:[w windowNumber]
		 context:nil
		 eventNumber:xEvent->xany.serial
		 clickCount:1
		 pressure:1.0];

  } else {

    e = [NSEvent mouseEventWithType:NSMouseMoved
		 location:eventLocation
		 modifierFlags:eventFlags
		 timestamp:(NSTimeInterval)xEvent->xbutton.time
		 windowNumber:[w windowNumber]
		 context:nil
		 eventNumber:xEvent->xany.serial
		 clickCount:0
		 pressure:0.0];
  }

  return e;
}

NSEvent *
process_mouse_up(XEvent *xEvent)
{
  unsigned int eventFlags;
  NSEventType eventType;
  NSPoint eventLocation;
  NSEvent *e;
  NSWindow *w;
  NSRect r;

  NSLog(@"Process mouseUp\n");

  eventFlags = process_modifier_flags(xEvent->xbutton.state);
        
  if (xEvent->xbutton.button == Button1) {
    eventType = NSLeftMouseUp;
  } else {
    eventType = NSRightMouseUp;
  }

  // construct location in window
  // need to flip coordinates to be in postscript coordinates
  w = nswindow_for_xwindow(xEvent->xbutton.window);
  r = [w frame];
  eventLocation.x = xEvent->xbutton.x;
  eventLocation.y = r.size.height - xEvent->xbutton.y;

  e = [NSEvent mouseEventWithType:eventType
	       location:eventLocation
	       modifierFlags:xEvent->xbutton.state
	       timestamp:(NSTimeInterval)xEvent->xbutton.time
	       windowNumber:[w windowNumber]
	       context:nil
	       eventNumber:xEvent->xany.serial
	       clickCount:1
	       pressure:1.0];

  return e;
}

NSEvent *
process_key_down(XEvent *xEvent)
{
  char buf[256];
  int count;
  XComposeStatus compose;
  NSString *keys, *ukeys;
  KeySym keysym;
  NSPoint eventLocation;
  unsigned short keyCode;
  unsigned int eventFlags;
  NSEvent *e;
  NSWindow *w;
  NSRect r;

  NSLog(@"Process keyDown\n");

  eventFlags = process_modifier_flags(xEvent->xkey.state);
    
  count = XLookupString(xEvent, buf, 256, &keysym, &compose);

  /* Make sure that the string is properly terminated */
		      
  if (count > 255) {
    buf[255] = '\0';
  } else if (count < 1) {
    buf[0] = '\0';
  } else {
    buf[count] = '\0';
  }

  // construct location in window
  // need to flip coordinates to be in postscript coordinates
  w = nswindow_for_xwindow(xEvent->xkey.window);
  r = [w frame];
  eventLocation.x = xEvent->xkey.x;
  eventLocation.y = r.size.height - xEvent->xkey.y;

  keyCode = process_key_code(xEvent, keysym, eventFlags);
    
  ukeys = [NSString stringWithCString:buf];
  keys = ukeys; /* Stupid implementation (to be replaced) */
    
  e = [NSEvent keyEventWithType:NSKeyDown
	       location:eventLocation
	       modifierFlags:eventFlags
	       timestamp:(NSTimeInterval)xEvent->xkey.time
	       windowNumber:[w windowNumber]
	       context:nil
	       characters:keys
	       charactersIgnoringModifiers:ukeys
	       isARepeat:NO
	       keyCode:keyCode];

  return e;
}

NSEvent *
process_key_up(XEvent *xEvent)
{
  char buf[256];
  int count;
  XComposeStatus compose;
  NSString *keys, *ukeys;
  KeySym keysym;
  unsigned int eventFlags;
  NSPoint eventLocation;
  unsigned short keyCode;
  NSEvent *e;
  NSWindow *w;
  NSRect r;

  NSLog(@"Process keyUp\n");

  eventFlags = process_modifier_flags(xEvent->xkey.state);
    
  count = XLookupString(xEvent, buf, 256, &keysym, &compose);

    /* Make sure that the string is properly terminated */
    
  if (count > 255) {
    buf[255] = '\0';
  } else if (count < 1) {
    buf[0] = '\0';
  } else {
    buf[count] = '\0';
  }

  keyCode = process_key_code(xEvent, keysym, eventFlags);
    
  ukeys = [NSString stringWithCString:buf];
  keys = ukeys; /* Stupid implementation (to be replaced) */    
    
  // construct location in window
  // need to flip coordinates to be in postscript coordinates
  w = nswindow_for_xwindow(xEvent->xkey.window);
  r = [w frame];
  eventLocation.x = xEvent->xkey.x;
  eventLocation.y = r.size.height - xEvent->xkey.y;
    
  e = [NSEvent keyEventWithType:NSKeyUp
	       location:eventLocation
	       modifierFlags:eventFlags
	       timestamp:(NSTimeInterval)xEvent->xkey.time
	       windowNumber:[w windowNumber]
	       context:nil
	       characters:keys
	       charactersIgnoringModifiers:ukeys
	       isARepeat:NO
	       keyCode:keyCode];

  return e;
}

unsigned short
process_key_code(XEvent *xEvent, KeySym keysym,
		 unsigned int eventModifierFlags)
{
  unsigned short keyCode = 0;

  if ((keysym == XK_Return) ||
      (keysym == XK_KP_Enter) ||
      (keysym == XK_Linefeed))
    {
      /* do nothing for now */
	
    } else if ((keysym >= XK_Shift_L) && (keysym <= XK_Hyper_R)) {

      /*
       * The shift button is depressed.  This should have already
       * been detected in the process_modifier_flags function.  Therefore,
       * nothing is done here...
       */
    }

  /* if a function key was pressed */
    
  if ((keysym >= XK_F1) && (keysym <= XK_F35)) {

    eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
	
    switch(xEvent->xkey.keycode) {
    case XK_F1: keyCode = NSF1FunctionKey; break;
    case XK_F2: keyCode = NSF2FunctionKey; break;
    case XK_F3: keyCode = NSF3FunctionKey; break;
    case XK_F4: keyCode = NSF4FunctionKey; break;
    case XK_F5: keyCode = NSF5FunctionKey; break;
    case XK_F6: keyCode = NSF6FunctionKey; break;
    case XK_F7: keyCode = NSF7FunctionKey; break;
    case XK_F8: keyCode = NSF8FunctionKey; break;
    case XK_F9: keyCode = NSF9FunctionKey; break;
    case XK_F10: keyCode = NSF10FunctionKey; break;
    case XK_F11: keyCode = NSF11FunctionKey; break;
    case XK_F12: keyCode = NSF12FunctionKey; break;
    case XK_F13: keyCode = NSF13FunctionKey; break;
    case XK_F14: keyCode = NSF14FunctionKey; break;
    case XK_F15: keyCode = NSF15FunctionKey; break;
    case XK_F16: keyCode = NSF16FunctionKey; break;
    case XK_F17: keyCode = NSF17FunctionKey; break;
    case XK_F18: keyCode = NSF18FunctionKey; break;
    case XK_F19: keyCode = NSF19FunctionKey; break;
    case XK_F20: keyCode = NSF20FunctionKey; break;
    case XK_F21: keyCode = NSF21FunctionKey; break;
    case XK_F22: keyCode = NSF22FunctionKey; break;
    case XK_F23: keyCode = NSF23FunctionKey; break;
    case XK_F24: keyCode = NSF24FunctionKey; break;
    case XK_F25: keyCode = NSF25FunctionKey; break;
    case XK_F26: keyCode = NSF26FunctionKey; break;
    case XK_F27: keyCode = NSF27FunctionKey; break;
    case XK_F28: keyCode = NSF28FunctionKey; break;
    case XK_F29: keyCode = NSF29FunctionKey; break;
    case XK_F30: keyCode = NSF30FunctionKey; break;
    case XK_F31: keyCode = NSF31FunctionKey; break;
    case XK_F32: keyCode = NSF32FunctionKey; break;
    case XK_F33: keyCode = NSF33FunctionKey; break;
    case XK_F34: keyCode = NSF34FunctionKey; break;
    case XK_F35: keyCode = NSF35FunctionKey; break;

    default: /* do nothing */
    }
  } else {
    if ((keysym == XK_BackSpace) || (keysym == XK_Delete)) {
      keyCode = NSDeleteFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Home) {
      keyCode = NSHomeFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Left) {
      keyCode = NSLeftArrowFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Up) {
      keyCode = NSUpArrowFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Right) {
      keyCode = NSRightArrowFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Down) {
      keyCode = NSDownArrowFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Prior) {
      keyCode = NSPrevFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Page_Up) {
      keyCode = NSPageUpFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Next) {
      keyCode = NSNextFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Page_Down) {
      keyCode = NSPageDownFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_End) {
      keyCode = NSEndFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Begin) {
      keyCode = NSBeginFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Select) {
      keyCode = NSSelectFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Print) {
      keyCode = NSPrintFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Execute) {
      keyCode = NSExecuteFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Insert) {
      keyCode = NSInsertFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Undo) {
      keyCode = NSUndoFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Redo) {
      keyCode = NSRedoFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Menu) {
      keyCode = NSMenuFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Find) {
      keyCode = NSFindFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 

#if 0
    } else if (keysym == XK_Cancel) {
      keyCode = NSSystemFunctionKey; /* ??? */		
#endif

    } else if (keysym == XK_Help) {
      keyCode = NSHelpFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Break) {
      keyCode = NSBreakFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask;    
    } else if (keysym == XK_Mode_switch) {
      keyCode = NSModeSwitchFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 

#if 0	
    } else if (keysym == XK_script_switch) {
      keyCode = NSSystemFunctionKey; /* ??? */
    } else if (keysym == XK_Num_Lock) {
      keyCode = NSSystemFunctionKey; /* ??? */
#endif
    } else if (keysym == XK_Sys_Req) {
      keyCode = NSSysReqFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Scroll_Lock) {
      keyCode = NSScrollLockFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Pause) {
      keyCode = NSPauseFunctionKey;		
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if (keysym == XK_Clear) {
      keyCode = NSClearDisplayFunctionKey;
      eventModifierFlags = eventModifierFlags | NSFunctionKeyMask; 
    } else if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) {
      eventModifierFlags = eventModifierFlags |
	NSFunctionKeyMask |
	NSShiftKeyMask; 
    } else if ((keysym == XK_Control_L) || (keysym == XK_Control_R)) {
      eventModifierFlags = eventModifierFlags |
	NSFunctionKeyMask |
	NSControlKeyMask; 
    } else if (keysym == XK_Alt_R) {
      eventModifierFlags = eventModifierFlags |
	NSFunctionKeyMask |
	NSAlternateKeyMask; 
    } else if (keysym == XK_Alt_L) {
      eventModifierFlags = eventModifierFlags |
	NSFunctionKeyMask |
	NSCommandKeyMask; 
    }
  }
    
  /* If the key press originated from the key pad */
    
  if ((keysym >= XK_KP_Space) && (keysym <= XK_KP_9)) {
    eventModifierFlags = eventModifierFlags | NSNumericPadKeyMask;

    switch(keysym) {
    case XK_KP_F1:        keyCode = NSF1FunctionKey;         break;
    case XK_KP_F2:        keyCode = NSF2FunctionKey;         break;
    case XK_KP_F3:        keyCode = NSF3FunctionKey;         break;
    case XK_KP_F4:        keyCode = NSF4FunctionKey;         break;
    case XK_KP_Home:      keyCode = NSHomeFunctionKey;       break;
    case XK_KP_Left:      keyCode = NSLeftArrowFunctionKey;  break;
    case XK_KP_Up:        keyCode = NSUpArrowFunctionKey;    break;
    case XK_KP_Right:     keyCode = NSRightArrowFunctionKey; break;
    case XK_KP_Down:      keyCode = NSDownArrowFunctionKey;  break;
    case XK_KP_Prior:     keyCode = NSPrevFunctionKey;       break;
      //case XK_KP_Page_Up:   keyCode = NSPageUpFunctionKey;     break;
    case XK_KP_Next:      keyCode = NSNextFunctionKey;       break;
      //case XK_KP_Page_Down: keyCode = NSPageDownFunctionKey;   break;
    case XK_KP_End:       keyCode = NSEndFunctionKey;        break;
    case XK_KP_Begin:     keyCode = NSBeginFunctionKey;      break;
    case XK_KP_Insert:    keyCode = NSInsertFunctionKey;     break;
    case XK_KP_Delete:    keyCode = NSDeleteFunctionKey;     break;
	    
    default:  break;  /* Nothing to do */
    }
  } /* End of keypad stuff */

  if (((keysym >= XK_KP_Space) && (keysym <= XK_KP_9)) ||
      ((keysym >= XK_space) && (keysym <= XK_asciitilde)))
    {	
      /* Not processed */
    }

  return keyCode;
}

/*
 * process_modifier_flags determines which modifier keys (Command, Control,
 * Shift, and so forth) were held down while the event occured and
 * sets the eventModifierFlags instance variable accordingly.
 */
    
unsigned int
process_modifier_flags(unsigned int state)
{
  unsigned int eventModifierFlags = 0; /* Clear the mask */

  if (state & ControlMask) {
    eventModifierFlags = eventModifierFlags | NSControlKeyMask;
  }

  if (state & ShiftMask) {
    eventModifierFlags = eventModifierFlags | NSShiftKeyMask;
  }

  if (state & Mod1Mask) {
    eventModifierFlags = eventModifierFlags | NSCommandKeyMask; /* ? */
    fprintf(stdout, "setButtonModifierFlags(): Mod1Mask\n");
  }

  if (state & Mod2Mask) {
    eventModifierFlags = eventModifierFlags | NSAlternateKeyMask;/* ? */
    fprintf(stdout, "setButtonModifierFlags(): Mod2Mask\n");
  }

  if (state & Mod3Mask) {
    eventModifierFlags = eventModifierFlags | NSAlphaShiftKeyMask;/* ? */
    fprintf(stdout, "setButtonModifierFlags(): Mod3Mask\n");
  }

  if (state & Mod4Mask) {
    eventModifierFlags = eventModifierFlags | NSHelpKeyMask; /* ? */
    fprintf(stdout, "setButtonModifierFlags(): Mod4Mask\n");
  }

  if (state & Mod5Mask) {
    eventModifierFlags = eventModifierFlags | NSControlKeyMask; /* ? */
    fprintf(stdout, "setButtonModifierFlags(): Mod5Mask\n");
  }

  return eventModifierFlags;
}

