#include "Settings.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "WindowManager.h"

/* Display Manager code copied from Apple's DisplayVideo example */
/* I HATE THE DISPLAY MANAGER!! <Insert rant here> */
struct DepthInfo {
  VDSwitchInfoRec depthSwitchInfo; // This is the switch mode to choose this timing/depth
  VPBlock depthVPBlock; // VPBlock (including size, depth and format)
};
typedef struct DepthInfo DepthInfo;

struct ListIteratorDataRec {
  unsigned long displayModeFlags;
  VDSwitchInfoRec displayModeSwitchInfo;
  VDResolutionInfoRec displayModeResolutionInfo;
  VDTimingInfoRec displayModeTimingInfo; // Contains timing flags and such
  unsigned long depthBlockCount; // How many depths available for a particular timing
  DepthInfo * depthBlocks; // Array of DepthInfo
  Str255 displayModeName; // name of the timing mode
};
typedef struct ListIteratorDataRec ListIteratorDataRec;

static pascal void ModeListIterator(void * userData, DMListIndexType itemIndex, DMDisplayModeListEntryPtr displaymodeInfo) {
  #pragma unused(itemIndex)
  unsigned long depthCount;
  short iCount;
  ListIteratorDataRec * myIterateData = (ListIteratorDataRec *) userData;
  DepthInfo * myDepthInfo;
  
  myIterateData->displayModeFlags = displaymodeInfo->displayModeFlags; // Info on this particular display mode
  myIterateData->displayModeSwitchInfo = *displaymodeInfo->displayModeSwitchInfo; // not needed - depth info has this per depth
  myIterateData->displayModeResolutionInfo = *displaymodeInfo->displayModeResolutionInfo; // refresh rate, pixels/lines at max depth 
  myIterateData->displayModeTimingInfo = *displaymodeInfo->displayModeTimingInfo; // to get the flags on timing mode
  myIterateData->displayModeName[0] = sprintf((char *) &myIterateData->displayModeName[1], "%.*s", displaymodeInfo->displayModeName[0], &displaymodeInfo->displayModeName[1]);	// the name of the mode
  
  // now get the DMDepthInfo into memory we own
  depthCount = displaymodeInfo->displayModeDepthBlockInfo->depthBlockCount;
  myDepthInfo = (DepthInfo *) NewPtrClear(depthCount * sizeof(DepthInfo));
   
  // set the info for the caller
  myIterateData->depthBlockCount = depthCount;
  myIterateData->depthBlocks = myDepthInfo;
  
  // and fill out all the entries
  for (iCount = 0; iCount < depthCount; iCount++) {
    myDepthInfo[iCount].depthSwitchInfo = *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthSwitchInfo;
    myDepthInfo[iCount].depthVPBlock = *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthVPBlock;
  }
}

static void SquashDisplayModeList(VSettings * s) {
  ScreenResolution * current, * target, * previous;
  
  current = s->Resolutions;
  while (current != NULL) {
    target = current->next;
    previous = current;
    while (target != NULL) {
      if (target->Width == current->Width && target->Height == current->Height && target->RefreshRate == current->RefreshRate) {
        previous->next = target->next;
        DisposePtr((Ptr) target);
        target = previous->next;
        continue;
      }
      previous = target;
      target = target->next;
    }
    current = current->next;
  }
}

static void GetDisplayCapabilities(VSettings * s) {
  GDHandle device;
  DisplayIDType displayID;
  DMListIndexType displayModeCount;
  DMListType displayModeList;
  ListIteratorDataRec searchData;
  short wDisplayMode, wDepth;
  DMDisplayModeListIteratorUPP iteratorProc;
  OSErr error;
  ScreenResolution ** currentScreenResHandle;
  
  s->NumberOfResolutions = 0;
  device = DMGetFirstScreenDevice(dmOnlyActiveDisplays);
  error = DMGetDisplayIDByGDevice(device, &displayID, 0);
  if (error != noErr) return;
  displayModeCount = 0;
  error = DMNewDisplayModeList(displayID, 0, 0, &displayModeCount, &displayModeList);
  if (error != noErr) return;
  currentScreenResHandle = &s->Resolutions;
  searchData.depthBlocks = NULL;
  iteratorProc = NewDMDisplayModeListIteratorUPP(ModeListIterator);
  for (wDisplayMode = 0; wDisplayMode < displayModeCount; wDisplayMode++) {
    DMGetIndexedDisplayModeFromList(displayModeList, wDisplayMode, 0, iteratorProc, &searchData);
    for (wDepth = 0; wDepth < searchData.depthBlockCount; wDepth++) {
      *currentScreenResHandle = (ScreenResolution *) NewPtr(sizeof(ScreenResolution));
      if (*currentScreenResHandle == NULL) continue;
      s->NumberOfResolutions++;
      (**currentScreenResHandle).Width = searchData.depthBlocks[wDepth].depthVPBlock.vpBounds.right;
      (**currentScreenResHandle).Height = searchData.depthBlocks[wDepth].depthVPBlock.vpBounds.bottom;
      (**currentScreenResHandle).RefreshRate = (searchData.displayModeResolutionInfo.csRefreshRate >> 16);
      (**currentScreenResHandle).ColorDepth = searchData.depthBlocks[wDepth].depthVPBlock.vpPixelSize;
      (**currentScreenResHandle).next = NULL;
      currentScreenResHandle = &(**currentScreenResHandle).next;
    }
    if (searchData.depthBlocks != NULL) {
      DisposePtr((Ptr) searchData.depthBlocks);
      searchData.depthBlocks = NULL;
    }
  }
  DisposeDMDisplayModeListIteratorUPP(iteratorProc);
  SquashDisplayModeList(s);
  DMDisposeList(displayModeList);
}

static void ReadSettingsFromDisk(VSettings * s) {
  FSSpec file;
  short refNum;
  OSErr error;
  char line[255];
  int temp;
  
  error = FindFolder(kOnSystemDisk, kPreferencesFolderType, 1, &file.vRefNum, &file.parID);
  if (error != noErr) return;
  error = FSMakeFSSpec(file.vRefNum, file.parID, "\pInfiltration preferences", &file);
  if (error != noErr) return;
  error = FSpOpenDF(&file, fsRdPerm, &refNum);
  if (error != noErr) return;
  while (ReadLn(refNum, line)) {
    if (!memcmp(line, "FullScreenResolution:", 21)) {
      sscanf(line, "FullScreenResolution: %d", &temp);
      s->FullScreenResolution = temp;
    } else if (!memcmp(line, "SoundEnabled:", 13)) {
      sscanf(line, "SoundEnabled: %d", &temp);
      s->SoundEnabled = temp;
    } else if (!memcmp(line, "NoFilledPolys:", 14)) {
      sscanf(line, "NoFilledPolys: %d", &temp);
      s->NoFilledPolys = temp;
    } else if (!memcmp(line, "StartInFullScreen:", 18)) {
      sscanf(line, "StartInFullScreen: %d", &temp);
      s->StartInFullScreen = temp;
    } else if (!memcmp(line, "Left:", 5))
      sscanf(line, "Left: %hd", &s->Left);
    else if (!memcmp(line, "Right:", 6))
      sscanf(line, "Right: %hd", &s->Right);
    else if (!memcmp(line, "Up:", 3))
      sscanf(line, "Up: %hd", &s->Up);
    else if (!memcmp(line, "Down:", 5))
      sscanf(line, "Down: %hd", &s->Down);
    else if (!memcmp(line, "Forward:", 8))
      sscanf(line, "Forward: %hd", &s->Forward);
    else if (!memcmp(line, "Backward:", 9))
      sscanf(line, "Backward: %hd", &s->Backward);
    else if (!memcmp(line, "Bullet:", 7))
      sscanf(line, "Bullet: %hd", &s->Bullet);
    else if (!memcmp(line, "RocketTarget:", 13))
      sscanf(line, "RocketTarget: %hd", &s->RocketTarget);
    else if (!memcmp(line, "Rocket:", 7))
      sscanf(line, "Rocket: %hd", &s->Rocket);
    else if (!memcmp(line, "Brake:", 6))
      sscanf(line, "Brake: %hd", &s->Brake);
    else if (!memcmp(line, "Pause:", 6))
      sscanf(line, "Pause: %hd", &s->Pause);
  }
  FSClose(refNum);
}

static void SaveSettingsToDisk(VSettings * s) {
  FSSpec file;
  long length;
  short refNum;
  OSErr error;
  char line[255];
  
  error = FindFolder(kOnSystemDisk, kPreferencesFolderType, 1, &file.vRefNum, &file.parID);
  if (error != noErr) return;
  error = FSMakeFSSpec(file.vRefNum, file.parID, "\pInfiltration preferences", &file);
  if (error == fnfErr) error = FSpCreate(&file, 'Vect', 'Pref', smRoman);
  if (error != noErr) return;
  error = FSpOpenDF(&file, fsWrPerm, &refNum);
  if (error != noErr) return;
  SetEOF(refNum, 0);
  length = sprintf(line, "FullScreenResolution: %d\n", s->FullScreenResolution);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "SoundEnabled: %d\n", s->SoundEnabled);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "NoFilledPolys: %d\n", s->NoFilledPolys);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "StartInFullScreen: %d\n", s->StartInFullScreen);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Left: %d\n", s->Left);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Right: %d\n", s->Right);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Up: %d\n", s->Up);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Down: %d\n", s->Down);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Forward: %d\n", s->Forward);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Backward: %d\n", s->Backward);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Bullet: %d\n", s->Bullet);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "RocketTarget: %d\n", s->RocketTarget);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Rocket: %d\n", s->Rocket);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Brake: %d\n", s->Brake);
  FSWrite(refNum, &length, line);
  length = sprintf(line, "Pause: %d\n", s->Pause);
  FSWrite(refNum, &length, line);
  FSClose(refNum);
}

void InitSettings(VSettings * s) {
  SetSettings(s);
  s->Left = 28;
  s->Right = 29;
  s->Up = 30;
  s->Down = 31;
  s->Forward = ' ';
  s->Backward = (' ' | shiftKey);
  s->Bullet = 'f';
  s->RocketTarget = '\t';
  s->Rocket = 'r';
  s->Brake = 'b';
  s->Pause = 'p';
  
  s->KeyBeingSet = NULL;
  
  s->SoundEnabled = 1;
  s->NoFilledPolys = 0;
  s->StartInFullScreen = 0;
  
  s->FullScreenResolution = FULLSCREENRESNOCHANGE;
  
  s->Resolutions = NULL;
  s->NumberOfResolutions = 0;
  GetDisplayCapabilities(s);
  s->Window = NULL;
  
  ReadSettingsFromDisk(s);
}

void CleanUpSettings(VSettings * s) {
  ScreenResolution * res;
  
  while (s->Resolutions != NULL) {
    res = s->Resolutions->next;
    DisposePtr((Ptr) s->Resolutions);
    s->Resolutions = res;
  }
  if (s->Window != NULL) {
    DisposeWindow(s->Window);
    s->Window = NULL;
  }
  SaveSettingsToDisk(s);
}

static int GetKeyDescription(UInt16 key, char * string) {
  unsigned char charCode;
  int length = 0;
  
  if (key & optionKey) length += sprintf((string + length), "Option + ");
  if (key & cmdKey) length += sprintf((string + length), "Cmd + ");
  if (key & shiftKey) length += sprintf((string + length), "Shift + ");
  if (key & controlKey) length += sprintf((string + length), "Ctrl + ");
  charCode = (key & 0x00FF);
  switch (charCode) {
    case 3:
      length += sprintf((string + length), "Enter");
      break;
    case 8:
      length += sprintf((string + length), "Backspace");
      break;
    case 9:
      length += sprintf((string + length), "Tab");
      break;
    case 10:
    case 13:
      length += sprintf((string + length), "Return");
      break;
    case 27:
      length += sprintf((string + length), "Escape");
      break;
    case 28:
      length += sprintf((string + length), "Left arrow");
      break;
    case 29:
      length += sprintf((string + length), "Right arrow");
      break;
    case 30:
      length += sprintf((string + length), "Up arrow");
      break;
    case 31:
      length += sprintf((string + length), "Down arrow");
      break;
    case ' ': /* Normal space */
    case ' ': /* Non-breaking space */
      length += sprintf((string + length), "Space");
      break;
    case 127:
      length += sprintf((string + length), "Forward delete");
      break;
    default:
      length += sprintf((string + length), "%c", charCode);
      break;
  }
  return length;
}

SInt16 KeyWithModifiers(unsigned char charCode, UInt32 modifiers) {
  switch (charCode) {
    case 3:
    case 8:
    case 9:
    case 10:
    case 13:
    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case ' ': /* Space */
    case ' ': /* Non-breaking space */
    case 127:
      /* Char code is not visibly affected by modifiers */
      return ((SInt16) charCode | modifiers);
    default:
      /* Char code is visibly affected by modifiers; don't bother displaying Shift + or Option + */
      return ((SInt16) charCode | (modifiers & ~(shiftKey | optionKey)));
  }
}

static void UpdateKeySettingDisplay(VSettings * s, UInt16 * theKey) {
  ControlRef theControl = NULL;
  char string[256];
  ControlID controlID;
  int length;
  
  controlID.signature = 'idsi';
  if (theKey == &s->Left) {
    controlID.id = LOOKLEFTKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Right) {
    controlID.id = LOOKRIGHTKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Down) {
    controlID.id = LOOKDOWNKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Up) {
    controlID.id = LOOKUPKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Forward) {
    controlID.id = MOVEFORWARDKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Backward) {
    controlID.id = MOVEBACKWARDKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Bullet) {
    controlID.id = BULLETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Rocket) {
    controlID.id = ROCKETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->RocketTarget) {
    controlID.id = ROCKETTARGETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Brake) {
    controlID.id = BRAKEKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (theKey == &s->Pause) {
    controlID.id = PAUSEKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  }
  if (theControl != NULL) {
    length = GetKeyDescription(*theKey, string);
    SetControlData(theControl, kControlEditTextPart, kControlEditTextTextTag, length, string);
    Draw1Control(theControl);
  }
}

static void ClearKeyDisplayStyles(VSettings * s) {
  ControlRef theControl = NULL;
  ControlID controlID;
  ControlFontStyleRec fontStyle;
  
  controlID.signature = 'idsi';
  if (s->KeyBeingSet == &s->Left) {
    controlID.id = LOOKLEFTKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Right) {
    controlID.id = LOOKRIGHTKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Down) {
    controlID.id = LOOKDOWNKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Up) {
    controlID.id = LOOKUPKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Forward) {
    controlID.id = MOVEFORWARDKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Backward) {
    controlID.id = MOVEBACKWARDKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Bullet) {
    controlID.id = BULLETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Rocket) {
    controlID.id = ROCKETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->RocketTarget) {
    controlID.id = ROCKETTARGETKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Brake) {
    controlID.id = BRAKEKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  } else if (s->KeyBeingSet == &s->Pause) {
    controlID.id = PAUSEKEYDISPLAY;
    GetControlByID(s->Window, &controlID, &theControl);
  }
  if (theControl != NULL) {
    fontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
    fontStyle.size = 12;
    fontStyle.font = systemFont;
    SetControlFontStyle(theControl, &fontStyle);
    Draw1Control(theControl);
  }
}

static void HiliteKeySettingDisplay(ControlRef control) {
  ControlFontStyleRec fontStyle;
  
  fontStyle.flags = (kControlUseForeColorMask | kControlUseSizeMask | kControlUseFontMask | kControlUseFaceMask);
  fontStyle.foreColor.red = fontStyle.foreColor.green = 0x0000;
  fontStyle.foreColor.blue = 0x7FFF;
  fontStyle.size = 12;
  fontStyle.font = systemFont;
  fontStyle.style = italic;
  SetControlFontStyle(control, &fontStyle);
  Draw1Control(control);
}

static void DefaultSettings(VSettings * s) {
  ControlRef theControl = NULL;
  ControlID controlID;
  
  s->Left = 28;
  s->Right = 29;
  s->Up = 30;
  s->Down = 31;
  s->Forward = ' ';
  s->Backward = (' ' | shiftKey);
  s->Bullet = 'f';
  s->RocketTarget = '\t';
  s->Rocket = 'r';
  s->Brake = 'b';
  s->Pause = 'p';
  UpdateKeySettingDisplay(s, &s->Left);
  UpdateKeySettingDisplay(s, &s->Right);
  UpdateKeySettingDisplay(s, &s->Up);
  UpdateKeySettingDisplay(s, &s->Down);
  UpdateKeySettingDisplay(s, &s->Forward);
  UpdateKeySettingDisplay(s, &s->Backward);
  UpdateKeySettingDisplay(s, &s->Bullet);
  UpdateKeySettingDisplay(s, &s->RocketTarget);
  UpdateKeySettingDisplay(s, &s->Rocket);
  UpdateKeySettingDisplay(s, &s->Brake);
  UpdateKeySettingDisplay(s, &s->Pause);
  
  ClearKeyDisplayStyles(s);
  s->KeyBeingSet = NULL;
  
  controlID.signature = 'idsi';
  
  s->SoundEnabled = 1;
  /*
  controlID.id = SOUNDENABLEDCHECKBOX;
  GetControlByID(s->Window, &controlID, &theControl);
  SetControlValue(theControl, s->SoundEnabled);
  */
  
  s->NoFilledPolys = 0;
  controlID.id = NOPOLYGONFILLCHECKBOX;
  GetControlByID(s->Window, &controlID, &theControl);
  SetControlValue(theControl, s->NoFilledPolys);
  
  s->StartInFullScreen = 0;
  controlID.id = STARTINFULLSCREENCHECKBOX;
  GetControlByID(s->Window, &controlID, &theControl);
  SetControlValue(theControl, s->StartInFullScreen);
  
  s->SoundEnabled = 1;
  controlID.id = SOUNDENABLEDCHECKBOX;
  GetControlByID(s->Window, &controlID, &theControl);
  SetControlValue(theControl, s->SoundEnabled);
  
  s->FullScreenResolution = FULLSCREENRESNOCHANGE;
  controlID.id = FULLSCREENRESMENU;
  GetControlByID(s->Window, &controlID, &theControl);
  SetControlValue(theControl, s->FullScreenResolution);
}

/* Settings window code copied from Life */
static pascal OSStatus SettingsWindowEventHandler(EventHandlerCallRef nextEvent, EventRef theEvent, void * userData) {
  #pragma unused(nextEvent, theEvent, userData)
  short controlValue;
  ControlRef control;
  Rect bounds;
  VSettings * s;
  SInt32 controlReference;
  unsigned char charCode;
  UInt32 modifiers;
  ControlID controlID;
  
  s = (VSettings *) userData;
  switch (GetEventClass(theEvent)) {
    case kEventClassWindow:
      switch (GetEventKind(theEvent)) {
        case kEventWindowClose:
          TransWindow(s->Window, 0);
          DisposeWindow(s->Window);
          s->Window = NULL;
          return noErr;
        case kEventWindowDrawContent:
          GetWindowPortBounds(s->Window, &bounds);
          EraseRect(&bounds);
          DrawControls(s->Window);
          return eventNotHandledErr;
      }
      break;
    case kEventClassControl:
      switch (GetEventKind(theEvent)) {
        case kEventControlHit:
          GetEventParameter(theEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
          controlReference = GetControlReference(control);
          switch (controlReference) {
            case FULLSCREENRESMENU:
              controlValue = GetControlValue(control);
              if (controlValue < 3) s->FullScreenResolution = FULLSCREENRESNOCHANGE;
              else s->FullScreenResolution = (controlValue - 3);
              break;
            case STARTINFULLSCREENCHECKBOX:
              controlValue = !GetControlValue(control);
              SetControlValue(control, controlValue);
              s->StartInFullScreen = controlValue;
              break;
            case NOPOLYGONFILLCHECKBOX:
              controlValue = !GetControlValue(control);
              SetControlValue(control, controlValue);
              s->NoFilledPolys = controlValue;
              break;
            case SOUNDENABLEDCHECKBOX:
              controlValue = !GetControlValue(control);
              SetControlValue(control, controlValue);
              s->SoundEnabled = controlValue;
              break;
            case SETLOOKLEFTKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Left;
              controlID.signature = 'idsi';
              controlID.id = LOOKLEFTKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETLOOKRIGHTKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Right;
              controlID.signature = 'idsi';
              controlID.id = LOOKRIGHTKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETLOOKDOWNKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Down;
              controlID.signature = 'idsi';
              controlID.id = LOOKDOWNKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETLOOKUPKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Up;
              controlID.signature = 'idsi';
              controlID.id = LOOKUPKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETMOVEFORWARDKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Forward;
              controlID.signature = 'idsi';
              controlID.id = MOVEFORWARDKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETMOVEBACKWARDKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Backward;
              controlID.signature = 'idsi';
              controlID.id = MOVEBACKWARDKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETBULLETKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Bullet;
              controlID.signature = 'idsi';
              controlID.id = BULLETKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETROCKETKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Rocket;
              controlID.signature = 'idsi';
              controlID.id = ROCKETKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETROCKETTARGETKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->RocketTarget;
              controlID.signature = 'idsi';
              controlID.id = ROCKETTARGETKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETBRAKEKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Brake;
              controlID.signature = 'idsi';
              controlID.id = BRAKEKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case SETPAUSEKEYBUTTON:
              if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s);
              s->KeyBeingSet = &s->Pause;
              controlID.signature = 'idsi';
              controlID.id = PAUSEKEYDISPLAY;
              GetControlByID(s->Window, &controlID, &control);
              HiliteKeySettingDisplay(control);
              break;
            case DEFAULTSBUTTON:
              DefaultSettings(s);
              break;
          }
          break;
      }
      break;
    case kEventClassKeyboard:
      switch (GetEventKind(theEvent)) {
        case kEventRawKeyDown:
          if (s->KeyBeingSet != NULL) {
            GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode);
            GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
            if (charCode != 27) {
              *s->KeyBeingSet = KeyWithModifiers(charCode, modifiers);
              UpdateKeySettingDisplay(s, s->KeyBeingSet);
            }
            ClearKeyDisplayStyles(s);
            s->KeyBeingSet = NULL;
            return noErr;
          }
          break;
      }
      break;
  }
  return eventNotHandledErr;
}

/* Sorry for the scary code... I guess that's what I get for not using nibs. :/ */
void OpenSettingsWindow(VSettings * s) {
  Rect bounds;
  GWorldPtr origGWorld;
  GDHandle origGDevice, mainDevice;
  Point screenSize;
  EventTypeSpec windowEventTypes[] = {{kEventClassWindow, kEventWindowClose}, {kEventClassWindow, kEventWindowDrawContent}, {kEventClassKeyboard, kEventRawKeyDown}}, controlEventTypes[] = {{kEventClassControl, kEventControlHit}};
  ControlRef theControl;
  EventHandlerUPP eventHandlerUPP;
  MenuRef screenResMenu;
  ScreenResolution * screenRes;
  Str255 itemName;
  int currentItemNumber;
  ControlFontStyleRec controlFontStyle;
  CFStringRef string;
  Boolean locked = 1;
  char keyDescription[256];
  ControlID controlID;
  
  if (s->Window != NULL) {
    BringToFront(s->Window);
    SelectWindow(s->Window);
    return;
  }
  
  mainDevice = GetMainDevice();
  screenSize.h = (**mainDevice).gdRect.right;
  screenSize.v = (**mainDevice).gdRect.bottom;
  SetRect(&bounds, ((screenSize.h / 2) - 200), ((screenSize.v / 2) - 238), ((screenSize.h / 2) + 200), ((screenSize.v / 2) + 238));
  s->Window = NewCWindow(NULL, &bounds, "\pSettings", 0, noGrowDocProc, (WindowPtr) -1, 1, 0);
  if (s->Window == NULL) return;
  GetGWorld(&origGWorld, &origGDevice);
  SetPortWindowPort(s->Window);
  SetThemeBackground(kThemeBrushDialogBackgroundActive, 32, 1);
  OffsetRect(&bounds, -bounds.left, -bounds.top);
  EraseRect(&bounds);
  InstallStandardEventHandler(GetWindowEventTarget(s->Window));
  eventHandlerUPP = NewEventHandlerUPP(SettingsWindowEventHandler);
  InstallWindowEventHandler(s->Window, eventHandlerUPP, 3, windowEventTypes, s, NULL);
  
  CreateRootControl(s->Window, &theControl);
  
  screenResMenu = GetMenuHandle(140);
  if (screenResMenu == NULL) {
    screenResMenu = NewMenu(140, "\p");
    AppendMenu(screenResMenu, "\pNo change");
    if (s->NumberOfResolutions > 0) AppendMenu(screenResMenu, "\p(-");
    currentItemNumber = 3;
    for (screenRes = s->Resolutions; screenRes != NULL; screenRes = screenRes->next) {
      itemName[0] = sprintf((char *) &itemName[1], "%d x %d, %dHz", screenRes->Width, screenRes->Height, screenRes->RefreshRate);
      AppendMenu(screenResMenu, "\pN");
      SetMenuItemText(screenResMenu, currentItemNumber, itemName);
      currentItemNumber++;
    }
    InsertMenu(screenResMenu, kInsertHierarchicalMenu);
  }
  SetRect(&bounds, 10, 10, 390, 30);
  CreatePopupButtonControl(s->Window, &bounds, CFSTR("Fullscreen resolution"), 140, 0, 150, 0, 0, &theControl);
  if (s->FullScreenResolution == FULLSCREENRESNOCHANGE) SetControlValue(theControl, 1);
  else SetControlValue(theControl, (s->FullScreenResolution + 3));
  SetControlReference(theControl, FULLSCREENRESMENU);
  controlID.signature = 'idsi';
  controlID.id = FULLSCREENRESMENU;
  SetControlID(theControl, &controlID);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  SetRect(&bounds, 50, 40, 390, 54);
  CreateCheckBoxControl(s->Window, &bounds, CFSTR("Start in full screen mode"), s->StartInFullScreen, 0, &theControl);
  SetControlReference(theControl, STARTINFULLSCREENCHECKBOX);
  controlID.signature = 'idsi';
  controlID.id = STARTINFULLSCREENCHECKBOX;
  SetControlID(theControl, &controlID);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  SetRect(&bounds, 50, 60, 390, 74);
  CreateCheckBoxControl(s->Window, &bounds, CFSTR("Don't fill polygons"), s->NoFilledPolys, 0, &theControl);
  SetControlReference(theControl, NOPOLYGONFILLCHECKBOX);
  controlID.signature = 'idsi';
  controlID.id = NOPOLYGONFILLCHECKBOX;
  SetControlID(theControl, &controlID);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  SetRect(&bounds, 50, 80, 390, 94);
  CreateCheckBoxControl(s->Window, &bounds, CFSTR("Play sounds"), s->SoundEnabled, 0, &theControl);
  SetControlReference(theControl, SOUNDENABLEDCHECKBOX);
  controlID.signature = 'idsi';
  controlID.id = SOUNDENABLEDCHECKBOX;
  SetControlID(theControl, &controlID);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teCenter;
  SetRect(&bounds, 10, 108, 390, 124);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Keys"), &controlFontStyle, &theControl);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 134, 100, 150);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Look left:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 134, 290, 150);
  GetKeyDescription(s->Left, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = LOOKLEFTKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 132, 390, 152);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETLOOKLEFTKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 162, 100, 178);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Look right:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 162, 290, 178);
  GetKeyDescription(s->Right, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = LOOKRIGHTKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 160, 390, 180);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETLOOKRIGHTKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 190, 100, 206);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Look down:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 190, 290, 206);
  GetKeyDescription(s->Down, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = LOOKDOWNKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 188, 390, 208);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETLOOKDOWNKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 218, 100, 234);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Look up:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 218, 290, 234);
  GetKeyDescription(s->Up, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = LOOKUPKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 216, 390, 236);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETLOOKUPKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 246, 100, 262);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Accelerate:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 246, 290, 262);
  GetKeyDescription(s->Forward, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = MOVEFORWARDKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 244, 390, 264);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETMOVEFORWARDKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 274, 100, 290);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Reverse:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 274, 290, 290);
  GetKeyDescription(s->Backward, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = MOVEBACKWARDKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 272, 390, 292);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETMOVEBACKWARDKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 302, 100, 318);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Fire:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 302, 290, 318);
  GetKeyDescription(s->Bullet, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = BULLETKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 300, 390, 320);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETBULLETKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 330, 100, 346);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Rocket:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 330, 290, 346);
  GetKeyDescription(s->Rocket, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = ROCKETKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 328, 390, 348);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETROCKETKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 358, 100, 374);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Rocket target:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 358, 290, 374);
  GetKeyDescription(s->RocketTarget, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = ROCKETTARGETKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 356, 390, 376);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETROCKETTARGETKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 386, 100, 402);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Brake:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 386, 290, 402);
  GetKeyDescription(s->Brake, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = BRAKEKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 384, 390, 404);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETBRAKEKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  controlFontStyle.flags = kControlUseJustMask;
  controlFontStyle.just = teFlushRight;
  SetRect(&bounds, 10, 414, 100, 430);
  CreateStaticTextControl(s->Window, &bounds, CFSTR("Pause:"), &controlFontStyle, &theControl);
  
  SetRect(&bounds, 110, 414, 290, 430);
  GetKeyDescription(s->Pause, keyDescription);
  string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription);
  controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask);
  controlFontStyle.size = 12;
  controlFontStyle.font = systemFont;
  CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl);
  CFRelease(string);
  SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked);
  controlID.signature = 'idsi';
  controlID.id = PAUSEKEYDISPLAY;
  SetControlID(theControl, &controlID);
  
  SetRect(&bounds, 300, 412, 390, 432);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl);
  SetControlReference(theControl, SETPAUSEKEYBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  SetRect(&bounds, 155, 448, 245, 468);
  CreatePushButtonControl(s->Window, &bounds, CFSTR("Defaults"), &theControl);
  SetControlReference(theControl, DEFAULTSBUTTON);
  InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL);
  
  SetGWorld(origGWorld, origGDevice);
  
  TransWindow(s->Window, 1);
}

/* Silly function written to avoid using a global variable */
VSettings * SettingsAccessor(VSettings * s) {
  static VSettings * settings = NULL;
  
  if (s != NULL) settings = s;
  return settings;
}

void GetFullscreenSettings(VSettings * s, int * Width, int * Height, int * RefreshRate) {
  int count;
  
  if (s->FullScreenResolution == FULLSCREENRESNOCHANGE) {
    GDHandle mainDevice;
    
    mainDevice = GetMainDevice();
    *Width = (**mainDevice).gdRect.right;
    *Height = (**mainDevice).gdRect.bottom;
    *RefreshRate = 0;
  } else {
    ScreenResolution * res = s->Resolutions;
    for (count = 0; count < s->FullScreenResolution && res != NULL; count++) {
      res = res->next;
    }
    if (res == NULL) {
      GDHandle mainDevice;
      
      mainDevice = GetMainDevice();
      *Width = (**mainDevice).gdRect.right;
      *Height = (**mainDevice).gdRect.bottom;
      *RefreshRate = 0;
      return;
    }
    *Width = res->Width;
    *Height = res->Height;
    *RefreshRate = res->RefreshRate;
  }
}

/* This function takes a key being pressed (KeyWithModifiers(charCode, modifiers)),
   and a key from the VSettings struct, and determines whether or not pressedKey
   can be considerered to be equivalent to setKey. The keys are equivalent if:
   1. Their char codes are the same,
   2. If there is no other key in the settings with the same modifiers as setKey,
      (pressedKey's modifiers & setKey's modifiers) >= setKey's modifiers,
   3. If there is another key in the settings with the same modifiers as setKey,
      pressedKey's modifiers == setKey's modifiers. 
   
   This code uses tolower to ignore case (the shift key). This is "good enough",
   but to work for all keys and modifiers, it would need to do such translations as
   ! -> 1, å -> a,  -> k, etc. */
Boolean SettingsIsEquivalentKey(VSettings * s, SInt16 pressedKey, SInt16 setKey) {
  Boolean strict;
  
  if ((s->Left != setKey && (s->Left & 0xFF) == (setKey & 0xFF) && (s->Left & 0x7F00)) ||
      (s->Right != setKey && (s->Right & 0xFF) == (setKey & 0xFF) && (s->Right & 0x7F00)) ||
      (s->Down != setKey && (s->Down & 0xFF) == (setKey & 0xFF) && (s->Down & 0x7F00)) ||
      (s->Up != setKey && (s->Up & 0xFF) == (setKey & 0xFF) && (s->Up & 0x7F00)) ||
      (s->Forward != setKey && (s->Forward & 0xFF) == (setKey & 0xFF) && (s->Forward & 0x7F00)) ||
      (s->Backward != setKey && (s->Backward & 0xFF) == (setKey & 0xFF) && (s->Backward & 0x7F00)) ||
      (s->Bullet != setKey && (s->Bullet & 0xFF) == (setKey & 0xFF) && (s->Bullet & 0x7F00)) ||
      (s->Rocket != setKey && (s->Rocket & 0xFF) == (setKey & 0xFF) && (s->Rocket & 0x7F00)) ||
      (s->Brake != setKey && (s->Brake & 0xFF) == (setKey & 0xFF) && (s->Brake & 0x7F00)) ||
      (s->Pause != setKey && (s->Pause & 0xFF) == (setKey & 0xFF) && (s->Pause & 0x7F00))) strict = 1;
  else strict = 0;
  if (strict && pressedKey != setKey) return 0;
  if (!strict) {
    pressedKey = (tolower(pressedKey & 0xFF) | (pressedKey & 0xFF00));
    setKey = (tolower(setKey & 0xFF) | (setKey & 0xFF00));
  }
  if ((pressedKey & (0xFF | (setKey & 0xFF00))) != setKey) return 0;
  return 1;
}
