https://github.com/virtualagc/virtualagc
Raw File
Tip revision: a8d66c8ae3c4d967053e2bfb4298e90182cbeff2 authored by Ron Burkey on 06 March 2024, 12:40:55 UTC
Minor tweaks associated with supporting Skylark 48.
Tip revision: a8d66c8
yaDSKY2.cpp
// -*- C++ -*- generated by wxGlade 0.6.3 on Fri Mar  6 23:28:00 2009
/*
 * Copyright 2009,2016,2017,2022 Ronald S. Burkey <info@sandroid.org>
 *
 * This file is part of yaAGC.
 *
 * yaAGC is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * yaAGC 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with yaAGC; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Filename:	yaDSKY2.cpp
 * Contact:	Ron Burkey <info@sandroid.org>
 * Reference:	http://www.ibiblio.org/apollo/index.html
 * Mods:	2009-03-06 RSB	Began adapting from yaDSKY.
 * 		2009-03-12 RSB	First working version.
 * 		2009-03-14 RSB	Added a workaround for a funky socket
 *				error which was showing up in Windows
 *				for the yaTelemetry program (which uses
 *				identical socket-management code) but
 *				which wasn't showing up here for some
 *				reason ... yet.  Eliminated some
 *				compiler warnings due to now-deprecated
 *				initializers for char *.
 *		2009-03-27 RSB	Added hotkeys.  They don't work, but I
 *				added them.
 *		2009-06-13 RSB	Added stuff for mapping verb-noun patterns
 *				to optional commands to be executed on the
 *				PC running the simulation.  This is all the
 *				stuff with names like *MATCH* or *Match*.
 *		2009-06-14 RSB	Added the "startup" pattern.
 *		2009-06-17 RSB	On Windows XP, a pop-up box appears at
 *				startup when DSKY2.matches doesn't exist.
 *				Silly me!  Why didn't I notice that?
 *				A separate check of the file's existence
 *				is now performed to eliminate that.
 *		2009-11-12 RSB	Changed the flashing duty cycle from 1:1
 *				to 3:1 (high:low) to match what Christian
 *				Bucher has found on the Apollo 11 TV
 *				transmissions.  Increased the flashing
 *				frequency as well, by about 20%.  It's
 *				still not accurate.
 *		2016-10-01 MAS	Converted several signals over to the new
 *				fictitious channel 163, driven by the AGC.
 *                              The flashing timing is now driven by the
 *                              AGC itself, as was the actual DSKY, and the
 *                              timing should be very accurate. RESTART and
 *                              STANDBY lights should now work. PROCEED has
 *                              been changed such that it can be held down,
 *                              so it's possible to go to standby.
 *		2016-10-05 MAS	Re-implemented PROCEED logic to be compatible
 *				with older wxwidgets.
 *		2016-11-02 MAS	Made + higher priority than - when both sign
 *				bits are set, based on newly discovered
 *                              diagrams of DSKY relay wiring. This fixes
 *                              the Aurora12/Sunburst 120 DSKY relay test.
 *              2016-12-05 RSB  Changed EVT_CHAR to EVT_CHAR_HOOK to make
 *                              hotkeys work.  Thanks to Chris Beecham for
 *                              sending in this fix!  It still doesn't work
 *                              quite right (for me, at least), in that the
 *                              hotkeys aren't recognized until at least
 *                              one click of the virtual buttons, but it's
 *                              a lot better than not working at all.
 *              2017-01-15 MAS  Set sane defaults for the indicators when
 *                              no config is present.
 *              2017-08-24 RSB	Eliminated a clang warning.
 *		2017-12-11 RSB	Added ability to click PROG indicator
 *				(for playback of pre-canned scripts).
 *		2017-12-12 RSB	Prevented from returning keystrokes to
 *				AGC during script playback.  Added keypad
 *				indications for logged keystrokes during
 *				playback.  Added ability to record, from
 *				TRACKER.
 *		2022-07-17 RSB  Made the window resizable by the user.
 *		                I'm not sure it really should be, but it
 *		                seems to fix some sizing problems that have
 *		                appeared with wxWidgets 3.2.
 *		2022-07-18 RSB  Apparently, on some platforms,
 *		                recordingFileOpen (and potentially lots
 *		                of other stuff is not being initialized,
 *		                and hence yaDSKY2 fails at startup when it
 *		                tries to write to garbage file pointers.
 *		                Now it's explicitly initialized.  But
 *		                who knows what else may be lurking?
 *
 * The yaDSKY2 program is intended to be a completely identical drop-in
 * replacement for the yaDSKY program as it exists at 2009-03-06.
 * yaDSKY works well, but it suffers from the basic problem that GTK+
 * support for Mac OS X (and even to some extent for Win32) is not
 * where I want it to be.  Furthermore, newer GUI programs for yaAGC
 * are based on wxWidgets, where I have been having better luck with
 * Win32/Mac support.  So in other words, yaDSKY2 is a wxWidgets port
 * of the GTK+ based yaDSKY program.
 */

#include "yaDSKY2.h"

#define VER(x) #x

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <iostream>

using namespace std;

#include "wx/filefn.h"
#include <wx/stdpaths.h>

#include "../yaAGC/yaAGC.h"
#include "../yaAGC/agc_engine.h"
#ifdef __clang__
extern "C" FILE *rfopen (const char *Filename, const char *mode);
#else
FILE *
rfopen (const char *Filename, const char *mode);
#endif

static MainFrame* MainWindow;
int HalfSize = 0;
#define PULSE_INTERVAL 80
static char DefaultHostname[] = "localhost";
char *Hostname = DefaultHostname;
static char NonDefaultHostname[129];
#ifdef WIN32
static int StartupDelay = 500;
#else
static int StartupDelay = 0;
#endif
static int DebugCounterMode = 0;
static int DebugCounterReg = 032, DebugCounterInc = 1, DebugCounterWhich = 1;
// TestUplink is set when we want to test the digital uplink by emitting
// keycodes on the digital uplink rather than on the DSKY channels.
static int TestUplink = 0;
static int ServerSocket = -1;
static bool ProceedPressed = false;

static const char SevenSeg0[] = "7Seg-0.jpg";

// Here are the defaults used for indicator lamps in the absence of a configuration file.
// In cases where we don't know that channel/bit corresponds to the lamp, we use 
// channel -1.

static const char UplinkActyOnJpeg[] = "UplinkActyOn.jpg", UplinkActyOffJpeg[] =
    "UplinkActyOff.jpg", NoAttOnJpeg[] = "NoAttOn.jpg", NoAttOffJpeg[] =
    "NoAttOff.jpg", StbyOnJpeg[] = "StbyOn.jpg", StbyOffJpeg[] = "StbyOff.jpg",
    KeyRelOnJpeg[] = "KeyRelOn.jpg", KeyRelOffJpeg[] = "KeyRelOff.jpg",
    OprErrOnJpeg[] = "OprErrOn.jpg", OprErrOffJpeg[] = "OprErrOff.jpg",
    PrioDispOnJpeg[] = "PrioDispOn.jpg", PrioDispOffJpeg[] = "PrioDispOff.jpg",
    NoDapOnJpeg[] = "NoDapOn.jpg", NoDapOffJpeg[] = "NoDapOff.jpg",
    TempOnJpeg[] = "TempOn.jpg", TempOffJpeg[] = "TempOff.jpg",
    GimbalLockOnJpeg[] = "GimbalLockOn.jpg", GimbalLockOffJpeg[] =
	"GimbalLockOff.jpg", ProgOnJpeg[] = "ProgOn.jpg", ProgOffJpeg[] =
	"ProgOff.jpg", RestartOnJpeg[] = "RestartOn.jpg", RestartOffJpeg[] =
	"RestartOff.jpg", TrackerOnJpeg[] = "TrackerOn.jpg", TrackerOffJpeg[] =
	"TrackerOff.jpg", AltOnJpeg[] = "AltOn.jpg",
    AltOffJpeg[] = "AltOff.jpg", VelOnJpeg[] = "VelOn.jpg", VelOffJpeg[] =
	"VelOff.jpg";

static Ind_t Inds[14] =
      {
	{				// 11
	  UplinkActyOnJpeg, UplinkActyOffJpeg, 011, 04, 0, 0, 0, 0, 0, 0 },
	  {				// 12
	  NoAttOnJpeg, NoAttOffJpeg, 010, 010, 0, 0, 0, 1, 074000, 060000 },
	  {				// 13
	  StbyOnJpeg, StbyOffJpeg, 0163, 0400, 0, 0, 0, 0, 0, 0 },
	  {				// 14
	  KeyRelOnJpeg, KeyRelOffJpeg, 0163, 020, 0, 0, 0, 0, 0, 0 },
	  {				// 15
	  OprErrOnJpeg, OprErrOffJpeg, 0163, 0100, 0, 0, 0, 0, 0, 0 },
	  {				// 16
	  PrioDispOnJpeg, PrioDispOffJpeg, 010, 01, 0, 0, 0, 1, 074000, 060000 },
	  {				// 17
	  NoDapOnJpeg, NoDapOffJpeg, 010, 02, 0, 0, 0, 1, 074000, 060000 },
	  {				// 21
	  TempOnJpeg, TempOffJpeg, 011, 010, 0, 0, 0, 0, 0, 0 },
	  {				// 22
	  GimbalLockOnJpeg, GimbalLockOffJpeg, 010, 040, 0, 0, 0, 1, 074000,
	      060000 },
	  {				// 23
	  ProgOnJpeg, ProgOffJpeg, 010, 0400, 0, 0, 0, 1, 074000, 060000 },
	  {				// 24
	  RestartOnJpeg, RestartOffJpeg, 0163, 0200, 0, 0, 0, 0, 0, 0 },
	  {				// 25
	  TrackerOnJpeg, TrackerOffJpeg, 010, 0200, 0, 0, 0, 1, 074000, 060000 },
	  {				// 26
	  AltOnJpeg, AltOffJpeg, 010, 020, 0, 0, 0, 1, 074000, 060000 },
	  {				// 27
	  VelOnJpeg, VelOffJpeg, 010, 04, 0, 0, 0, 1, 074000, 060000 } };

#define DEBUG(x) 

// The following stuff relates to a feature used for giving presentations, 
// in which patterns of DSKY keystrokes can be used to trigger commands on 
// the computer running the simulation.  All keystroke patterns begin with
// VERB, and contain at most one VERB.  The array of possible mappings is
// filled up at boot time from the file DSKY2.matches, if it exists, and is
// empty otherwise.  The buffer of actual keystrokes is, of course, filled
// at runtime.  The syntax in DSKY2.matches (which is an ASCII file) is that
// there is a separate line for each mapping, of the form:
//	pattern command
// The pattern consists of any string of the characters VN+-0123456788EPCRK
// followed by whitespace, followed by any string until the end-of-line is
// reached. 
#define MAX_MATCHES 100
typedef struct
{
  wxString *Pattern;
  wxString *Command;
} Match_t;
static wxString Match = wxT (" ");
static Match_t Matches[MAX_MATCHES] =
  { NULL };
static int NumMatches = 0;

// begin wxGlade: ::extracode
// end wxGlade

MainFrame::MainFrame (wxWindow* parent, int id, const wxString& title,
		      const wxPoint& pos, const wxSize& size, long style) :
    wxFrame (parent, id, title, pos, size,
	     wxCLOSE_BOX | wxMINIMIZE_BOX | wxCAPTION | wxSYSTEM_MENU | wxRESIZE_BORDER)
{
  // begin wxGlade: MainFrame::MainFrame
  panel_1 = new wxPanel (this, wxID_ANY);
  bitmap_5 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("FrameVertical.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_6_copy = new wxStaticBitmap (
      this, wxID_ANY,
      wxBitmap (wxT ("FrameHorizontal.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator11 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator21 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator12 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator22 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator13 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator23 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator14 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator24 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator15 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator25 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator16 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator26 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator17 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  Annunciator27 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("UplinkActyOff.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_6 = new wxStaticBitmap (
      this, wxID_ANY,
      wxBitmap (wxT ("FrameHorizontal.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_5_copy = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("FrameVertical.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_5_copy_1 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("FrameVertical.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_6_copy_copy = new wxStaticBitmap (
      this, wxID_ANY,
      wxBitmap (wxT ("FrameHorizontal.jpg"), wxBITMAP_TYPE_ANY));
  CompActyAnnunciator = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("CompActyOff.jpg"), wxBITMAP_TYPE_ANY));
  ModeAnnunciator = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("rProgOn.jpg"), wxBITMAP_TYPE_ANY));
  MD1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  MD2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  VerbAnnunciator = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("VerbOn.jpg"), wxBITMAP_TYPE_ANY));
  VD1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  VD2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  NounAnnunciator = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("NounOn.jpg"), wxBITMAP_TYPE_ANY));
  ND1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  ND2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_2_copy_1 = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("SeparatorOn.jpg"), wxBITMAP_TYPE_ANY));
  R1PlusMinus = new wxStaticBitmap (
      panel_1, wxID_ANY,
      wxBitmap (wxT ("PlusMinusOff.jpg"), wxBITMAP_TYPE_ANY));
  R1D1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R1D2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R1D3Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R1D4Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R1D5Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_2_copy = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("SeparatorOn.jpg"), wxBITMAP_TYPE_ANY));
  R2PlusMinus = new wxStaticBitmap (
      panel_1, wxID_ANY,
      wxBitmap (wxT ("PlusMinusOff.jpg"), wxBITMAP_TYPE_ANY));
  R2D1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R2D2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R2D3Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R2D4Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R2D5Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_2 = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("SeparatorOn.jpg"), wxBITMAP_TYPE_ANY));
  R3PlusMinus = new wxStaticBitmap (
      panel_1, wxID_ANY,
      wxBitmap (wxT ("PlusMinusOff.jpg"), wxBITMAP_TYPE_ANY));
  R3D1Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R3D2Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R3D3Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R3D4Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  R3D5Digit = new wxStaticBitmap (
      panel_1, wxID_ANY, wxBitmap (wxT ("7Seg-0.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_6_copy_copy_copy = new wxStaticBitmap (
      this, wxID_ANY,
      wxBitmap (wxT ("FrameHorizontal.jpg"), wxBITMAP_TYPE_ANY));
  bitmap_5_copy_2 = new wxStaticBitmap (
      this, wxID_ANY, wxBitmap (wxT ("FrameVertical.jpg"), wxBITMAP_TYPE_ANY));
  VerbBitmap = wxBitmap (wxT ("VerbUp.jpg"), wxBITMAP_TYPE_ANY);
  NounBitmap = wxBitmap (wxT ("NounUp.jpg"), wxBITMAP_TYPE_ANY);
  PlusBitmap = wxBitmap (wxT ("PlusUp.jpg"), wxBITMAP_TYPE_ANY);
  MinusBitmap = wxBitmap (wxT ("MinusUp.jpg"), wxBITMAP_TYPE_ANY);
  ZeroBitmap = wxBitmap (wxT ("0Up.jpg"), wxBITMAP_TYPE_ANY);
  SevenBitmap = wxBitmap (wxT ("7Up.jpg"), wxBITMAP_TYPE_ANY);
  FourBitmap = wxBitmap (wxT ("4Up.jpg"), wxBITMAP_TYPE_ANY);
  OneBitmap = wxBitmap (wxT ("1Up.jpg"), wxBITMAP_TYPE_ANY);
  EightBitmap = wxBitmap (wxT ("8Up.jpg"), wxBITMAP_TYPE_ANY);
  FiveBitmap = wxBitmap (wxT ("5Up.jpg"), wxBITMAP_TYPE_ANY);
  TwoBitmap = wxBitmap (wxT ("2Up.jpg"), wxBITMAP_TYPE_ANY);
  NineBitmap = wxBitmap (wxT ("9Up.jpg"), wxBITMAP_TYPE_ANY);
  SixBitmap = wxBitmap (wxT ("6Up.jpg"), wxBITMAP_TYPE_ANY);
  ThreeBitmap = wxBitmap (wxT ("3Up.jpg"), wxBITMAP_TYPE_ANY);
  ClrBitmap = wxBitmap (wxT ("ClrUp.jpg"), wxBITMAP_TYPE_ANY);
  ProBitmap = wxBitmap (wxT ("ProUp.jpg"), wxBITMAP_TYPE_ANY);
  KeyRelBitmap = wxBitmap (wxT ("KeyRelUp.jpg"), wxBITMAP_TYPE_ANY);
  EntrBitmap = wxBitmap (wxT ("EntrUp.jpg"), wxBITMAP_TYPE_ANY);
  RsetBitmap = wxBitmap (wxT ("RsetUp.jpg"), wxBITMAP_TYPE_ANY);
  VerbButton = new wxBitmapButton (this, ID_VERBBUTTON, VerbBitmap);
  NounButton = new wxBitmapButton (this, ID_NOUNBUTTON, NounBitmap);
  PlusButton = new wxBitmapButton (this, ID_PLUSBUTTON, PlusBitmap);
  MinusButton = new wxBitmapButton (this, ID_MINUSBUTTON, MinusBitmap);
  ZeroButton = new wxBitmapButton (this, ID_ZEROBUTTON, ZeroBitmap);
  SevenButton = new wxBitmapButton (this, ID_SEVENBUTTON, SevenBitmap);
  FourButton = new wxBitmapButton (this, ID_FOURBUTTON, FourBitmap);
  OneButton = new wxBitmapButton (this, ID_ONEBUTTON, OneBitmap);
  EightButton = new wxBitmapButton (this, ID_EIGHTBUTTON, EightBitmap);
  FiveButton = new wxBitmapButton (this, ID_FIVEBUTTON, FiveBitmap);
  TwoButton = new wxBitmapButton (this, ID_TWOBUTTON, TwoBitmap);
  NineButton = new wxBitmapButton (this, ID_NINEBUTTON, NineBitmap);
  SixButton = new wxBitmapButton (this, ID_SIXBUTTON, SixBitmap);
  ThreeButton = new wxBitmapButton (this, ID_THREEBUTTON, ThreeBitmap);
  ClrButton = new wxBitmapButton (this, ID_CLRBUTTON, ClrBitmap);
  ProButton = new wxBitmapButton (this, ID_PROBUTTON, ProBitmap);
  KeyRelButton = new wxBitmapButton (this, ID_KEYRELBUTTON, KeyRelBitmap);
  EntrButton = new wxBitmapButton (this, ID_ENTRBUTTON, EntrBitmap);
  RsetButton = new wxBitmapButton (this, ID_RSETBUTTON, RsetBitmap);

  ProButton->Connect (wxEVT_LEFT_DOWN,
		      wxMouseEventHandler (MainFrame::on_ProButton_pressed),
		      NULL,
		      this);
  Annunciator23->Connect (
      wxEVT_LEFT_DOWN,
      wxMouseEventHandler (MainFrame::on_Annunciator23_clicked), NULL, this);
  Annunciator25->Connect (
      wxEVT_LEFT_DOWN,
      wxMouseEventHandler (MainFrame::on_Annunciator25_clicked), NULL, this);
  scriptFileOpen = false;
  numScriptKeysPressed = 0;
  last11 = last13 = last163 = 0;
  for (int i = 0; i < 16; last10[i++] = 0)
    ;

  set_properties ();
  do_layout ();
  // end wxGlade
}

BEGIN_EVENT_TABLE(MainFrame, wxFrame)
// begin wxGlade: MainFrame::event_table
EVT_BUTTON(ID_VERBBUTTON, MainFrame::on_VerbButton_pressed)
EVT_BUTTON(ID_NOUNBUTTON, MainFrame::on_NounButton_pressed)
EVT_BUTTON(ID_PLUSBUTTON, MainFrame::on_PlusButton_pressed)
EVT_BUTTON(ID_MINUSBUTTON, MainFrame::on_MinusButton_pressed)
EVT_BUTTON(ID_ZEROBUTTON, MainFrame::on_ZeroButton_pressed)
EVT_BUTTON(ID_SEVENBUTTON, MainFrame::on_SevenButton_pressed)
EVT_BUTTON(ID_FOURBUTTON, MainFrame::on_FourButton_pressed)
EVT_BUTTON(ID_ONEBUTTON, MainFrame::on_OneButton_pressed)
EVT_BUTTON(ID_EIGHTBUTTON, MainFrame::on_EightButton_pressed)
EVT_BUTTON(ID_FIVEBUTTON, MainFrame::on_FiveButton_pressed)
EVT_BUTTON(ID_TWOBUTTON, MainFrame::on_TwoButton_pressed)
EVT_BUTTON(ID_NINEBUTTON, MainFrame::on_NineButton_pressed)
EVT_BUTTON(ID_SIXBUTTON, MainFrame::on_SixButton_pressed)
EVT_BUTTON(ID_THREEBUTTON, MainFrame::on_ThreeButton_pressed)
EVT_BUTTON(ID_CLRBUTTON, MainFrame::on_ClrButton_pressed)
EVT_BUTTON(ID_KEYRELBUTTON, MainFrame::on_KeyRelButton_pressed)
EVT_BUTTON(ID_ENTRBUTTON, MainFrame::on_EntrButton_pressed)
EVT_BUTTON(ID_RSETBUTTON, MainFrame::on_RsetButton_pressed)
EVT_BUTTON(ID_PROBUTTON, MainFrame::on_ProButton_released)
// end wxGlade
EVT_CHAR_HOOK(MainFrame::HotkeyEvent)
END_EVENT_TABLE();

void
MainFrame::HotkeyEvent (wxKeyEvent &KeyEvent)
{
  wxCommandEvent event;
  int k = KeyEvent.GetKeyCode ();
  //wxMessageBox ((char) k, wxT ("Info"));
  switch (k)
    {
    case '0':
      on_ZeroButton_pressed (event);
      break;
    case '1':
      on_OneButton_pressed (event);
      break;
    case '2':
      on_TwoButton_pressed (event);
      break;
    case '3':
      on_ThreeButton_pressed (event);
      break;
    case '4':
      on_FourButton_pressed (event);
      break;
    case '5':
      on_FiveButton_pressed (event);
      break;
    case '6':
      on_SixButton_pressed (event);
      break;
    case '7':
      on_SevenButton_pressed (event);
      break;
    case '8':
      on_EightButton_pressed (event);
      break;
    case '9':
      on_NineButton_pressed (event);
      break;
    case '+':
      on_PlusButton_pressed (event);
      break;
    case '-':
      on_MinusButton_pressed (event);
      break;
    case 'v':
    case 'V':
      on_VerbButton_pressed (event);
      break;
    case 'n':
    case 'N':
      on_NounButton_pressed (event);
      break;
    case 'e':
    case 'E':
      on_EntrButton_pressed (event);
      break;
    default:
      event.Skip ();
      break;
    }
}

void
MainFrame::on_VerbButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      DebugCounterWhich = 1;
      DebugCounterInc = 0;
    }
  else
    OutputKeycode (17);
  if (NumMatches)
    {
      Match = wxT ("V");
      MatchCheck ();
    }
}

void
MainFrame::on_NounButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      DebugCounterWhich = 0;
      DebugCounterReg = 0;
    }
  else
    OutputKeycode (31);
  if (NumMatches)
    {
      Match += wxT ("N");
      MatchCheck ();
    }
}

void
MainFrame::on_PlusButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (26);
  if (NumMatches)
    {
      Match += wxT ("+");
      MatchCheck ();
    }
}

void
MainFrame::on_MinusButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (27);
  if (NumMatches)
    {
      Match += wxT ("-");
      MatchCheck ();
    }
}

void
MainFrame::on_ZeroButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 0;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 0;
    }
  else
    OutputKeycode (16);
  if (NumMatches)
    {
      Match += wxT ("0");
      MatchCheck ();
    }
}

void
MainFrame::on_SevenButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 7;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 7;
    }
  else
    OutputKeycode (7);
  if (NumMatches)
    {
      Match += wxT ("7");
      MatchCheck ();
    }
}

void
MainFrame::on_FourButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 4;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 4;
    }
  else
    OutputKeycode (4);
  if (NumMatches)
    {
      Match += wxT ("4");
      MatchCheck ();
    }
}

void
MainFrame::on_OneButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 1;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 1;
    }
  else
    OutputKeycode (1);
  if (NumMatches)
    {
      Match += wxT ("1");
      MatchCheck ();
    }
}

void
MainFrame::on_EightButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (8);
  if (NumMatches)
    {
      Match += wxT ("8");
      MatchCheck ();
    }
}

void
MainFrame::on_FiveButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 5;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 5;
    }
  else
    OutputKeycode (5);
  if (NumMatches)
    {
      Match += wxT ("5");
      MatchCheck ();
    }
}

void
MainFrame::on_ThreeButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 3;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 3;
    }
  else
    OutputKeycode (3);
  if (NumMatches)
    {
      Match += wxT ("3");
      MatchCheck ();
    }
}

void
MainFrame::on_TwoButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 2;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 2;
    }
  else
    OutputKeycode (2);
  if (NumMatches)
    {
      Match += wxT ("2");
      MatchCheck ();
    }
}

void
MainFrame::on_NineButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (9);
  if (NumMatches)
    {
      Match += wxT ("9");
      MatchCheck ();
    }
}

void
MainFrame::on_SixButton_pressed (wxCommandEvent &event)
{
  if (DebugCounterMode)
    {
      if (DebugCounterWhich)
	DebugCounterInc = 6;
      else
	DebugCounterReg = (DebugCounterReg * 8) + 6;
    }
  else
    OutputKeycode (6);
  if (NumMatches)
    {
      Match += wxT ("6");
      MatchCheck ();
    }
}

void
MainFrame::on_ClrButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (30);
  if (NumMatches)
    {
      Match += wxT ("C");
      MatchCheck ();
    }
}

void
MainFrame::on_ProButton_pressed (wxMouseEvent &event)
{
  if (DebugCounterMode)
    {
      int j;
      unsigned char Packet[4];
      if (DebugCounterReg < 032 || DebugCounterReg > 060)
	return;
      if (DebugCounterInc < 0 || DebugCounterInc > 6)
	return;
      Packet[0] = 0x10 | ((DebugCounterReg >> 3) & 0x0f);
      Packet[1] = 0x40 | ((DebugCounterReg & 7) << 3);
      Packet[2] = 0x80;
      Packet[3] = 0xC0 | (DebugCounterInc & 7);
      //printf ("Reg=%02o Inc=%o Packet=%02x %02x %02x %02x\n",
      //	      DebugCounterReg, DebugCounterInc,
      //	      Packet[0], Packet[1], Packet[2], Packet[3]);
      if (ServerSocket != -1)
	{
	  j = send (ServerSocket, (const char *) Packet, 4, MSG_NOSIGNAL);
	  if (j == SOCKET_ERROR && SOCKET_BROKEN)
	    {
	      if (!DebugMode)
		printf ("Removing socket %d\n", ServerSocket);
#ifdef unix
	      close (ServerSocket);
#else
	      closesocket (ServerSocket);
#endif
	      ServerSocket = -1;
	    }
	}
    }
  else
    {
      // Press.
      OutputPro (0);
      ProceedPressed = true;
    }
  if (NumMatches)
    {
      Match += wxT ("P");
      MatchCheck ();
    }
  event.ResumePropagation (INT_MAX);
  event.Skip ();
}

void
MainFrame::scriptFileProcessLine (void)
{
  if (scriptFileCurrentLine >= scriptFileCount)
    return;
  wxString line = scriptFile.GetLine (scriptFileCurrentLine);
  if (3
      != wxSscanf (line, wxT ("%lf %o %o"), &scriptFileDifferentialTime,
		   &scriptFileChannelNumber, &scriptFileChannelValue))
    {
      scriptFileDifferentialTime = 0;
      scriptFileChannelNumber = 0;
      scriptFileChannelValue = 0;
    }
}

void
MainFrame::restoreToPrescript (void)
{
  scriptFileChannelNumber = 011;
  scriptFileChannelValue = last11;
  Timer->ActOnIncomingIO ((unsigned char *) NULL);
  scriptFileChannelNumber = 013;
  scriptFileChannelValue = last13;
  Timer->ActOnIncomingIO ((unsigned char *) NULL);
  scriptFileChannelNumber = 0163;
  scriptFileChannelValue = last163;
  Timer->ActOnIncomingIO ((unsigned char *) NULL);
  scriptFileChannelNumber = 010;
  for (int i = 1; i < 13; i++)
    {
      scriptFileChannelValue = (i << 11) + last10[i];
      Timer->ActOnIncomingIO ((unsigned char *) NULL);
    }
  numScriptKeysPressed = 0;
  // Note that when the script indicates a keypress, we Disable() that
  // key briefly and then reenable it.  This is done solely because it
  // was the only relatively-efficient way I could think to make a
  // visual indication of the button press ... yes, not very good in
  // terms of understandability, I know.  At any rate, we have to
  // make sure that the keys all get enabled at the end of the script.
  ProButton->Enable ();
  VerbButton->Enable ();
  NounButton->Enable ();
  ZeroButton->Enable ();
  OneButton->Enable ();
  TwoButton->Enable ();
  ThreeButton->Enable ();
  FourButton->Enable ();
  FiveButton->Enable ();
  SixButton->Enable ();
  SevenButton->Enable ();
  EightButton->Enable ();
  NineButton->Enable ();
  PlusButton->Enable ();
  MinusButton->Enable ();
  EntrButton->Enable ();
  ClrButton->Enable ();
  RsetButton->Enable ();
  KeyRelButton->Enable ();
}

void
MainFrame::on_Annunciator23_clicked (wxMouseEvent &event)
{
  // When you click on the PROG lamp, we want to:
  //	Save the current display settings (they're always already saved).
  //	Show a file-dialog to select a pre-canned script of i/o channel changes.
  //	Start playback of the pre-canned script, ignoring AGC commands
  //	After completion of playback,
  //		Show a message box.
  //		Restore the original display settings
  //		Quickly run through all of the pending commands from AGC.
  //		Start taking commands from the AGC again.
  if (recordingFileOpen)
    return;
  if (scriptFileOpen)
    {
      wxMessageBox (wxT ("Script aborted by user."));
      scriptFile.Close ();
      scriptFileOpen = false;
      restoreToPrescript ();
      return;
    }
  wxFileDialog* OpenDialog = new wxFileDialog (
      this, wxT ("Choose a pre-recorded i/o-channel script"), wxT ("."),
      wxEmptyString, wxT ("Scripts (*.canned)|*.canned"), wxFD_OPEN,
      wxDefaultPosition);
  if (OpenDialog->ShowModal () == wxID_OK) // if the user click "Open" instead of "Cancel"
    {
      wxString scriptPath = OpenDialog->GetPath ();
      scriptFile.Open (scriptPath);
      scriptFileCount = scriptFile.GetLineCount ();
      scriptFileCurrentLine = 0;
      scriptFileProcessLine ();
      scriptFileWaitUntil = scriptFileDifferentialTime;
      wxMessageBox (
	  wxT ("Script (") + wxString::Format (wxT ("%i"), scriptFileCount)
	      + wxT (" records) will start when this box closes."));
      scriptFileStopWatch.Start ();
      scriptFileOpen = true;
    }
  // Clean up after ourselves
  OpenDialog->Destroy ();
  event.ResumePropagation (INT_MAX);
  event.Skip ();
}

void
MainFrame::on_Annunciator25_clicked (wxMouseEvent &event)
{
  // When you first click on the TRACKER, we want to:
  //	Show a message box to say we're starting to record a canned script of i/o channel changes.
  //	Start recording.
  // When you subsequently click TRACKER, we want to:
  //	Stop recording
  if (scriptFileOpen)
    return;
  if (recordingFileOpen)
    {
      recordingFile.Write();
      recordingFile.Close ();
      recordingFileOpen = false;
      wxMessageBox (wxT ("Recording completed by user."));
    }
  else
    {
      wxMessageBox (wxT ("Recording will commence when this box is closed."));

      wxString documents = wxStandardPaths::Get().GetDocumentsDir();
      recordingFile.Create (documents + wxT("/yaDSKY2-recorded.canned"));
      recordingFileOpen = true;
      scriptFileStopWatch.Start ();
      recordingLastTime = 0;
    }
  event.ResumePropagation (INT_MAX);
  event.Skip ();
}

void
MainFrame::on_KeyRelButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (25);
  if (NumMatches)
    {
      Match += wxT ("K");
      MatchCheck ();
    }
}

void
MainFrame::on_EntrButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (28);
  if (NumMatches)
    {
      Match += wxT ("E");
      MatchCheck ();
    }
}

void
MainFrame::on_RsetButton_pressed (wxCommandEvent &event)
{
  OutputKeycode (18);
  if (NumMatches)
    {
      Match += wxT ("R");
      MatchCheck ();
    }
}

// wxGlade: add MainFrame event handlers

void
MainFrame::on_ProButton_released (wxCommandEvent &event)
{
  if (ProceedPressed)
    {
      OutputPro (1);
      ProceedPressed = false;
    }
}

void
MainFrame::set_properties ()
{
  // begin wxGlade: MainFrame::set_properties
  SetTitle (wxT ("yaDSKY2 by Ron Burkey"));
  wxIcon _icon;
  _icon.CopyFromBitmap (wxBitmap (wxT ("ApolloPatch2.png"), wxBITMAP_TYPE_ANY));
  SetIcon (_icon);
  panel_1->SetBackgroundColour (wxColour (160, 160, 160));
  VerbButton->SetMinSize (wxSize (75, 75));
  NounButton->SetMinSize (wxSize (75, 75));
  PlusButton->SetMinSize (wxSize (75, 75));
  MinusButton->SetMinSize (wxSize (75, 75));
  ZeroButton->SetMinSize (wxSize (75, 75));
  SevenButton->SetMinSize (wxSize (75, 75));
  FourButton->SetMinSize (wxSize (75, 75));
  OneButton->SetMinSize (wxSize (75, 75));
  EightButton->SetMinSize (wxSize (75, 75));
  FiveButton->SetMinSize (wxSize (75, 75));
  TwoButton->SetMinSize (wxSize (75, 75));
  NineButton->SetMinSize (wxSize (75, 75));
  SixButton->SetMinSize (wxSize (75, 75));
  ThreeButton->SetMinSize (wxSize (75, 75));
  ClrButton->SetMinSize (wxSize (75, 75));
  ProButton->SetMinSize (wxSize (75, 75));
  KeyRelButton->SetMinSize (wxSize (75, 75));
  EntrButton->SetMinSize (wxSize (75, 75));
  RsetButton->SetMinSize (wxSize (75, 75));
  // end wxGlade
}

void
MainFrame::do_layout ()
{
  // begin wxGlade: MainFrame::do_layout
  wxBoxSizer* sizer_1 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_3 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_4_copy = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_5_copy_3 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_5_copy_2 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_5_copy_1 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_5_copy = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_5 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_4 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_2 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_14 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_15 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_6 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_7 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_7_copy = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_7_copy_1 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_8 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_10_copy_1 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_11_copy_1 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_10_copy = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_11_copy = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_9 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_10 = new wxBoxSizer (wxVERTICAL);
  wxBoxSizer* sizer_11 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_12 = new wxBoxSizer (wxHORIZONTAL);
  wxBoxSizer* sizer_13 = new wxBoxSizer (wxVERTICAL);
  wxGridSizer* grid_sizer_1_copy = new wxGridSizer (7, 2, 9, 10);
  sizer_1->Add (20, 15, 0, 0, 0);
  sizer_2->Add (20, 20, 2, wxEXPAND, 0);
  sizer_12->Add (bitmap_5, 0, 0, 0);
  sizer_13->Add (bitmap_6_copy, 0, 0, 0);
  sizer_13->Add (20, 5, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator11, 0,
			  wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
			  0);
  grid_sizer_1_copy->Add (Annunciator21, 0,
			  wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
			  0);
  grid_sizer_1_copy->Add (Annunciator12, 0,
			  wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,
			  0);
  grid_sizer_1_copy->Add (Annunciator22, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator13, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator23, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator14, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator24, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator15, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator25, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator16, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator26, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator17, 0, 0, 0);
  grid_sizer_1_copy->Add (Annunciator27, 0, 0, 0);
  sizer_13->Add (grid_sizer_1_copy, 0,
		 wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0);
  sizer_13->Add (20, 5, 0, 0, 0);
  sizer_13->Add (bitmap_6, 0, 0, 0);
  sizer_12->Add (sizer_13, 0, 0, 0);
  sizer_12->Add (bitmap_5_copy, 0, 0, 0);
  sizer_2->Add (sizer_12, 0, 0, 0);
  sizer_2->Add (20, 20, 3, wxEXPAND, 0);
  sizer_14->Add (bitmap_5_copy_1, 0, 0, 0);
  sizer_15->Add (bitmap_6_copy_copy, 0, 0, 0);
  sizer_9->Add (CompActyAnnunciator, 0, wxALIGN_CENTER_VERTICAL, 0);
  sizer_9->Add (20, 20, 1, 0, 0);
  sizer_10->Add (ModeAnnunciator, 0, 0, 0);
  sizer_11->Add (MD1Digit, 0, 0, 0);
  sizer_11->Add (MD2Digit, 0, 0, 0);
  sizer_10->Add (sizer_11, 1, wxEXPAND, 0);
  sizer_9->Add (sizer_10, 1, wxEXPAND, 0);
  sizer_6->Add (sizer_9, 0, wxEXPAND, 0);
  sizer_6->Add (20, 14, 0, 0, 0);
  sizer_10_copy->Add (VerbAnnunciator, 0, 0, 0);
  sizer_11_copy->Add (VD1Digit, 0, 0, 0);
  sizer_11_copy->Add (VD2Digit, 0, 0, 0);
  sizer_10_copy->Add (sizer_11_copy, 0, wxEXPAND, 0);
  sizer_8->Add (sizer_10_copy, 1, wxEXPAND, 0);
  sizer_8->Add (20, 20, 1, 0, 0);
  sizer_10_copy_1->Add (NounAnnunciator, 0, 0, 0);
  sizer_11_copy_1->Add (ND1Digit, 0, 0, 0);
  sizer_11_copy_1->Add (ND2Digit, 0, 0, 0);
  sizer_10_copy_1->Add (sizer_11_copy_1, 1, wxEXPAND, 0);
  sizer_8->Add (sizer_10_copy_1, 1, wxEXPAND, 0);
  sizer_6->Add (sizer_8, 1, wxEXPAND, 0);
  sizer_6->Add (bitmap_2_copy_1, 0, wxALIGN_CENTER_HORIZONTAL, 0);
  sizer_7_copy_1->Add (R1PlusMinus, 0, 0, 0);
  sizer_7_copy_1->Add (R1D1Digit, 0, 0, 0);
  sizer_7_copy_1->Add (R1D2Digit, 0, 0, 0);
  sizer_7_copy_1->Add (R1D3Digit, 0, 0, 0);
  sizer_7_copy_1->Add (R1D4Digit, 0, 0, 0);
  sizer_7_copy_1->Add (R1D5Digit, 0, 0, 0);
  sizer_6->Add (sizer_7_copy_1, 0, wxEXPAND, 0);
  sizer_6->Add (bitmap_2_copy, 0, wxALIGN_CENTER_HORIZONTAL, 0);
  sizer_7_copy->Add (R2PlusMinus, 0, 0, 0);
  sizer_7_copy->Add (R2D1Digit, 0, 0, 0);
  sizer_7_copy->Add (R2D2Digit, 0, 0, 0);
  sizer_7_copy->Add (R2D3Digit, 0, 0, 0);
  sizer_7_copy->Add (R2D4Digit, 0, 0, 0);
  sizer_7_copy->Add (R2D5Digit, 0, 0, 0);
  sizer_6->Add (sizer_7_copy, 0, wxEXPAND, 0);
  sizer_6->Add (bitmap_2, 0, wxALIGN_CENTER_HORIZONTAL, 0);
  sizer_7->Add (R3PlusMinus, 0, 0, 0);
  sizer_7->Add (R3D1Digit, 0, 0, 0);
  sizer_7->Add (R3D2Digit, 0, 0, 0);
  sizer_7->Add (R3D3Digit, 0, 0, 0);
  sizer_7->Add (R3D4Digit, 0, 0, 0);
  sizer_7->Add (R3D5Digit, 0, 0, 0);
  sizer_6->Add (sizer_7, 0, wxEXPAND, 0);
  panel_1->SetSizer (sizer_6);
  sizer_15->Add (panel_1, 1, wxEXPAND, 0);
  sizer_15->Add (bitmap_6_copy_copy_copy, 0, 0, 0);
  sizer_14->Add (sizer_15, 0, 0, 0);
  sizer_14->Add (bitmap_5_copy_2, 0, 0, 0);
  sizer_2->Add (sizer_14, 0, 0, 0);
  sizer_2->Add (20, 20, 2, wxEXPAND, 0);
  sizer_1->Add (sizer_2, 0, wxEXPAND, 0);
  sizer_1->Add (20, 15, 0, 0, 0);
  sizer_3->Add (8, 20, 0, 0, 0);
  sizer_4->Add (20, 20, 1, 0, 0);
  sizer_4->Add (VerbButton, 0, 0, 0);
  sizer_4->Add (20, 5, 0, 0, 0);
  sizer_4->Add (NounButton, 0, 0, 0);
  sizer_4->Add (20, 20, 1, 0, 0);
  sizer_3->Add (sizer_4, 0, wxEXPAND, 0);
  sizer_3->Add (8, 20, 0, 0, 0);
  sizer_5->Add (PlusButton, 0, 0, 0);
  sizer_5->Add (20, 5, 0, 0, 0);
  sizer_5->Add (MinusButton, 0, 0, 0);
  sizer_5->Add (20, 5, 0, 0, 0);
  sizer_5->Add (ZeroButton, 0, 0, 0);
  sizer_3->Add (sizer_5, 0, 0, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_5_copy->Add (SevenButton, 0, 0, 0);
  sizer_5_copy->Add (20, 5, 0, 0, 0);
  sizer_5_copy->Add (FourButton, 0, 0, 0);
  sizer_5_copy->Add (20, 5, 0, 0, 0);
  sizer_5_copy->Add (OneButton, 0, 0, 0);
  sizer_3->Add (sizer_5_copy, 0, 0, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_5_copy_1->Add (EightButton, 0, 0, 0);
  sizer_5_copy_1->Add (20, 5, 0, 0, 0);
  sizer_5_copy_1->Add (FiveButton, 0, 0, 0);
  sizer_5_copy_1->Add (20, 5, 0, 0, 0);
  sizer_5_copy_1->Add (TwoButton, 0, 0, 0);
  sizer_3->Add (sizer_5_copy_1, 0, 0, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_5_copy_2->Add (NineButton, 0, 0, 0);
  sizer_5_copy_2->Add (20, 5, 0, 0, 0);
  sizer_5_copy_2->Add (SixButton, 0, 0, 0);
  sizer_5_copy_2->Add (20, 5, 0, 0, 0);
  sizer_5_copy_2->Add (ThreeButton, 0, 0, 0);
  sizer_3->Add (sizer_5_copy_2, 0, 0, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_5_copy_3->Add (ClrButton, 0, 0, 0);
  sizer_5_copy_3->Add (20, 5, 0, 0, 0);
  sizer_5_copy_3->Add (ProButton, 0, 0, 0);
  sizer_5_copy_3->Add (20, 5, 0, 0, 0);
  sizer_5_copy_3->Add (KeyRelButton, 0, 0, 0);
  sizer_3->Add (sizer_5_copy_3, 0, 0, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_4_copy->Add (20, 20, 1, 0, 0);
  sizer_4_copy->Add (EntrButton, 0, 0, 0);
  sizer_4_copy->Add (20, 5, 0, 0, 0);
  sizer_4_copy->Add (RsetButton, 0, 0, 0);
  sizer_4_copy->Add (20, 20, 1, 0, 0);
  sizer_3->Add (sizer_4_copy, 0, wxEXPAND, 0);
  sizer_3->Add (5, 20, 0, 0, 0);
  sizer_1->Add (sizer_3, 1, 0, 0);
  sizer_1->Add (20, 15, 0, 0, 0);
  SetSizer (sizer_1);
  sizer_1->Fit (this);
  Layout ();
  // end wxGlade
}

class yaDskyApp : public wxApp
{
public:
  bool
  OnInit ();
};

IMPLEMENT_APP (yaDskyApp)

bool
yaDskyApp::OnInit ()
{

  int i, j, UsedCfg = 0;

  wxInitAllImageHandlers ();
  MainWindow = new MainFrame (NULL, wxID_ANY, wxEmptyString);
  MainWindow->iLastButton = MainWindow->ProButton;
  MainWindow->CurrentBlank = wxString::FromAscii (SevenSeg0);
  MainWindow->CurrentVD1 = wxString::FromAscii (SevenSeg0);
  MainWindow->CurrentVD2 = wxString::FromAscii (SevenSeg0);
  MainWindow->CurrentND1 = wxString::FromAscii (SevenSeg0);
  MainWindow->CurrentND2 = wxString::FromAscii (SevenSeg0);
  SetTopWindow (MainWindow);

  // Put pointers to all of the indicator lamps into an array for
  // more-convenient access.
  Inds[0].Widget = MainWindow->Annunciator11;
  Inds[1].Widget = MainWindow->Annunciator12;
  Inds[2].Widget = MainWindow->Annunciator13;
  Inds[3].Widget = MainWindow->Annunciator14;
  Inds[4].Widget = MainWindow->Annunciator15;
  Inds[5].Widget = MainWindow->Annunciator16;
  Inds[6].Widget = MainWindow->Annunciator17;
  Inds[7].Widget = MainWindow->Annunciator21;
  Inds[8].Widget = MainWindow->Annunciator22;
  Inds[9].Widget = MainWindow->Annunciator23;
  Inds[10].Widget = MainWindow->Annunciator24;
  Inds[11].Widget = MainWindow->Annunciator25;
  Inds[12].Widget = MainWindow->Annunciator26;
  Inds[13].Widget = MainWindow->Annunciator27;

#ifdef ENABLE_NLS
  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);
#endif

  cout
      << string (
	  "yaDSKY2 Apollo DSKY simulation, ver " VER(NVER) ", built " __DATE__ " " __TIME__ "\n");
  cout << string ("Copyright 2009,2017,2022 by Ronald S. Burkey\n");
  cout
      << string (
	  "Refer to http://www.ibiblio.org/apollo/index.html for more information.\n");

  DEBUG (-1);

  Portnum = 19697;
  for (i = 1; i < argc; i++)
    {
      wxString Arg = argv[i];
      wxString ArgStart = Arg.BeforeFirst ('=');
      wxString ArgEnd = Arg.AfterFirst ('=');

      cout << string ("Arg ");
      cout << i;
      cout << string (" = \"");
      cout << string (Arg.mb_str ());
      cout << string ("\"\n");

      if (Arg.IsSameAs (wxT ("--relative-pixmaps")))
	{
	  // Does nothing.  Legacy from yaDSKY.
	}
      else if (Arg.IsSameAs (wxT ("--test-uplink")))
	TestUplink = 1;
      else if (Arg.IsSameAs (wxT ("--test-downlink")))
	{
	  // Does nothing.  Legacy from yaDSKY.
	}
      else if (ArgStart.IsSameAs (wxT ("--ip")))
	{
	  strcpy (NonDefaultHostname, ArgEnd.char_str ());
	  Hostname = NonDefaultHostname;
	}
      else if (ArgStart.IsSameAs (wxT ("--port")))
	{
	  long lPortnum;
	  ArgEnd.ToLong (&lPortnum);
	  Portnum = lPortnum;
	  if (Portnum <= 0 || Portnum >= 0x10000)
	    {
	      printf ("The --port switch is out of range.  Must be 1-64K.\n");
	      goto Help;
	    }
	}
      else if (ArgStart.IsSameAs (wxT ("--cfg")))
	{
	  if (MainWindow->ParseCfg (ArgEnd))
	    {
	      printf ("Aborting due to --cfg errors.\n");
	      goto Help;
	    }
	  UsedCfg = 1;
	}
      else if (Arg.IsSameAs (wxT ("--half-size")))
	{
	  if (UsedCfg)
	    {
	      printf (
		  "The --half-size switch must precede the --cfg switch.\n");
	      goto Help;
	    }
	  HalfSize = 1;
	  MainWindow->HalveTheWindow ();
	}
      else if (ArgStart.IsSameAs (wxT ("--delay")))
	{
	  long lj;
	  ArgEnd.ToLong (&lj);
	  StartupDelay = lj;
	}
      else if (Arg.IsSameAs (wxT ("--debug-counter-mode")))
	DebugCounterMode = 1;
      else
	{
	  Help: printf ("USAGE:\n");
	  printf ("\tyaDSKY2 [OPTIONS]\n");
	  printf ("The available options are:\n");
	  printf ("--ip=Hostname\n");
	  printf (
	      "\tThe yaDSKY2 program and the yaAGC Apollo Guidance Computer simulation\n");
	  printf (
	      "\texist in a \"client/server\" relationship, in which the yaDSKY2 program\n");
	  printf (
	      "\tneeds to be aware of the IP address or symbolic name of the host \n");
	  printf (
	      "\tcomputer running the yaAGC program.  By default, this is \"localhost\",\n");
	  printf (
	      "\tmeaning that both yaDSKY2 and yaAGC are running on the same computer.\n");
	  printf ("--port=Portnumber\n");
	  printf (
	      "\tBy default, yaDSKY2 attempts to connect to the yaAGC program using port\n");
	  printf (
	      "\tnumber %d.  However, if more than one instance of yaDSKY2 is being\n",
	      Portnum);
	  printf (
	      "\trun, or if yaAGC has been configured to listen on different ports, then\n");
	  printf (
	      "\tdifferent port settings for yaDSKY2 are needed.  Note that by default,\n");
	  printf ("\tyaAGC listens for new connections on ports %d-%d.\n",
		  Portnum, Portnum + 10 - 1);
	  printf ("--cfg=ConfigFilename\n");
	  printf (
	      "\tSelects a configuration file to be used, to allow different yaDSKY\n");
	  printf (
	      "\tsettings for LM vs. CM, or for different Apollo missions.  The \n");
	  printf (
	      "\tconfiguration files presently known are LM0.ini, LM.ini, LM1.ini, and CM.ini. \n");
	  printf (
	      "\tBy default (no --cfg switch) LM settings are used, but not the LM.ini\n");
	  printf ("\tfile itself.\n");
	  printf ("--half-size\n");
	  printf (
	      "\tUses a half-size version of yaDSKY2, suitable for smaller graphical\n");
	  printf ("\tdisplays.  If present, must precede --cfg.\n");
	  printf ("--delay=N\n");
	  printf (
	      "\t\"Start-up delay\", in ms.  Defaults to %d.  What the start-up\n",
	      StartupDelay);
	  printf (
	      "\tdelay does is to prevent yaDSKY2 from attempting to communicate with\n");
	  printf (
	      "\tyaAGC for a brief time after power-up.  This option is really only\n");
	  printf (
	      "\tuseful in Win32, to work around a problem with race-conditions in\n");
	  printf (
	      "\tthe start-up scripts like SimLuminary131.  When the race problem is\n");
	  printf (
	      "\tfixed correctly, this option will probably no longer be useful.\n");
	  printf ("--debug-counter-mode\n");
	  printf (
	      "\tThis is present only for debugging yaAGC\'s \"unprogrammed\"\n");
	  printf (
	      "\tcounter-increments, and has no useful purpose otherwise.  In this\n");
	  printf (
	      "\tthe simulated DSKY\'s do not have their normal interpretations and\n");
	  printf (
	      "\tcannot be used to affect the AGC CPU in any normal way.  Instead,\n");
	  printf (
	      "\tthe combination NOUN-digit-digit is used to specify an (octal)\n");
	  printf (
	      "\tCPU register number, and the combination VERB-digit is used\n");
	  printf (
	      "\tto select a counter-increment type as defined on the Virtual AGC\n");
	  printf (
	      "\twebsite\'s developer page.  The PRO key is used to send the selected\n");
	  printf (
	      "\tcounter-increment command to the AGC.  Note that there are no\n");
	  printf (
	      "\tvisual displays associated with this, since the AGC is still\n");
	  printf (
	      "\tcommanding the DSKY visual display in its usual way.  This mode\n");
	  printf (
	      "\tis terminated only by restarting yaDSKY2.  Only counter registers\n");
	  printf (
	      "\tin the range 32-60 (octal, default 32) are accepted, and only \n");
	  printf (
	      "\tincrement-types in the range 0-6 (default 1) are accepted.\n");
	  printf ("--test-uplink\n");
	  printf (
	      "\tIf this switch is used, keypresses are communicated to yaAGC\n");
	  printf ("\tas digital-uplink date instead of regular DSKY data.\n");
	  printf ("--test-downlink\n");
	  printf (
	      "\tDoes nothing. This switch is accepted only for backward compatibility.\n");
	  printf (
	      "\tIts former functionality has been replaced with the yaTelemetry program.\n");
	  printf ("--relative-pixmaps\n");
	  printf (
	      "\tDoes nothing. This switch is accepted only for backward compatibility.\n");
	  exit (1);
	}
    }DEBUG (0);

  cout << string ("Hostname=");
  cout << string (Hostname);
  cout << string (", port=");
  cout << Portnum;
  cout << string ("\n");

  // The following is sort of an abbreviated form of some stuff that 
  // ParseCfg does, and is called in case --cfg didn't appear on the 
  // command-line.
  if (!UsedCfg)
    {
      Ind_t *Indptr;
      // Update all of the indicator legends.  
      for (Indptr = Inds, i = 0; i < 14; Indptr++, i++)
	MainWindow->ImageSet (Indptr->Widget, Indptr->GraphicOff);
      MainWindow->ImageSet (MainWindow->iLastButton, "ProUp.jpg");
      MainWindow->KeyRelAnnunciator = Inds[3].Widget;
      MainWindow->CurrentKeyRel = MainWindow->BlankKeyRel =
	  wxString::FromAscii (Inds[3].GraphicOff);
      MainWindow->ImageSet (MainWindow->KeyRelAnnunciator,
			    MainWindow->CurrentKeyRel);
      MainWindow->OprErrAnnunciator = Inds[4].Widget;
      MainWindow->CurrentOprErr = MainWindow->BlankOprErr =
	  wxString::FromAscii (Inds[4].GraphicOff);
      MainWindow->ImageSet (MainWindow->OprErrAnnunciator,
			    MainWindow->CurrentOprErr);
    }

  // Read the optional DSKY2.matches file.
  wxTextFile Fin;
  if (wxFileExists (wxT ("DSKY2.matches")))
    {
      if (Fin.Open (wxT ("DSKY2.matches")))
	{
	  int i;
	  NumMatches = Fin.GetLineCount ();
	  for (i = 0; i < NumMatches; i++)
	    {
	      wxString Line;
	      Line = Fin.GetLine (i);
	      Matches[i].Pattern = new wxString (Line.BeforeFirst (' '));
	      Matches[i].Command = new wxString (Line.AfterFirst (' '));
	      if (Matches[i].Pattern->IsSameAs (wxT ("startup")))
		wxExecute (*Matches[i].Command, wxEXEC_ASYNC);
	    }
	  Fin.Close ();
	}
    }

  MainWindow->recordingFileOpen = false;

  MainWindow->Timer = new TimerClass ();
  MainWindow->Timer->Start (PULSE_INTERVAL);

  // With wxWidgets 3.0, the --half-size option inevitably creates a main
  // window thats too short (vertically), and I haven't been able to figure
  // out how to coax it into calculating the window size properly.
  // (Works fine with wxWidgets 2.8 or with the full-size DSKY.)  At any
  // rate, the following is a lame attempt to prevent that from happening,
  // though in theory it could force windows that are too big on some
  // platforms, alas!  With wxWidgets 3.2, the problem extends to
  // half-size windows that are a lot too big in general or regular-size
  // windows that are a little too small.
  if (HalfSize)
    {
      MainWindow->SetMinSize (wxSize(330, 392));
    }
  MainWindow->Show ();
  return true;
}

//-------------------------------------------------------------------------
// This function is called every PULSE_INTERVAL milliseconds.  It manages
// the server connection, and causes display-updates based on input from
// yaAGC.

void
TimerClass::Notify ()
{
  static unsigned char Packet[4];
  static int PacketSize = 0;
  int i;
  unsigned char c;
  static unsigned long pulseCount = 0;

  pulseCount++;

#if 0 
  // Just a preliminary debugging thing, to check out how well bitmap
  // replacement works. 
  static int j = 0, k = 0;
  k++;
  if (k >= 10)
    {
      k = 0;
      j = !j;
      if (j)
      MainWindow->ImageSet (MainWindow->Annunciator11, "OprErrOnO.jpg");
      else
      MainWindow->ImageSet (MainWindow->Annunciator11, "OprErrOff.jpg");
    }
#endif

  if (StartupDelay > 0)
    {
      StartupDelay -= PULSE_INTERVAL;
      return;
    }
  // Process canned script, if any, rather than actual packets from yaAGC.
  if (MainWindow->scriptFileOpen)
    {
      int i, j;
      // If any buttons that have been pressed (and hence are Disabled) have
      // timed out (and hence need to be Enabled), then fix them.
      for (j = 0; j < MainWindow->numScriptKeysPressed; j++)
	if (pulseCount >= MainWindow->scriptKeysPressed[j].whenPressed + 4)
	  MainWindow->scriptKeysPressed[j].button->Enable ();
	else
	  break;
      if (j > 0)
	{
	  MainWindow->numScriptKeysPressed -= j;
	  for (i = 0; i < MainWindow->numScriptKeysPressed; i++, j++)
	    {
	      MainWindow->scriptKeysPressed[i].whenPressed =
		  MainWindow->scriptKeysPressed[j].whenPressed;
	      MainWindow->scriptKeysPressed[i].button =
		  MainWindow->scriptKeysPressed[j].button;
	    }
	}
      // Now check the script for new records.
      while (true)
	{
	  if (MainWindow->scriptFileCurrentLine >= MainWindow->scriptFileCount)
	    {
	      MainWindow->scriptFile.Close ();
	      MainWindow->scriptFileOpen = false;
	      wxMessageBox (
		  wxT ("Script completed, time ")
		      + wxString::Format (
			  wxT("%.2f"),
			  MainWindow->scriptFileStopWatch.Time () / 1000.0)
		      + wxT (" seconds."));
	      MainWindow->restoreToPrescript ();
	      break;
	    }
	  else if (MainWindow->scriptFileStopWatch.Time ()
	      >= MainWindow->scriptFileWaitUntil)
	    {

	      MainWindow->scriptFileCurrentLine++;
	      MainWindow->scriptFileProcessLine ();
	      if (MainWindow->scriptFileChannelNumber == 015)
		{
		  // These are actually AGC input ports, and hence are
		  // outputs from the DSKY rather than inputs.  The
		  // only thing we do with this info is to temporarily
		  // Disable() the key widget, so as to give it a slightly
		  // different appearance.
		  int keycode = MainWindow->scriptFileChannelValue & 0x1F;
		  int i;
		  wxBitmapButton *button;
		  switch (keycode)
		    {
		    case 16:
		      button = MainWindow->ZeroButton;
		      break;
		    case 1:
		      button = MainWindow->OneButton;
		      break;
		    case 2:
		      button = MainWindow->TwoButton;
		      break;
		    case 3:
		      button = MainWindow->ThreeButton;
		      break;
		    case 4:
		      button = MainWindow->FourButton;
		      break;
		    case 5:
		      button = MainWindow->FiveButton;
		      break;
		    case 6:
		      button = MainWindow->SixButton;
		      break;
		    case 7:
		      button = MainWindow->SevenButton;
		      break;
		    case 8:
		      button = MainWindow->EightButton;
		      break;
		    case 9:
		      button = MainWindow->NineButton;
		      break;
		    case 17:
		      button = MainWindow->VerbButton;
		      break;
		    case 18:
		      button = MainWindow->RsetButton;
		      break;
		    case 25:
		      button = MainWindow->KeyRelButton;
		      break;
		    case 26:
		      button = MainWindow->PlusButton;
		      break;
		    case 27:
		      button = MainWindow->MinusButton;
		      break;
		    case 28:
		      button = MainWindow->EntrButton;
		      break;
		    case 30:
		      button = MainWindow->ClrButton;
		      break;
		    case 31:
		      button = MainWindow->NounButton;
		      break;
		    default:
		      button = NULL;
		      break;
		    }
		  if (button != NULL)
		    {
		      for (i = 0; i < MainWindow->numScriptKeysPressed; i++)
			if (MainWindow->scriptKeysPressed[i].button == button)
			  break;
		      if (i < MainWindow->numScriptKeysPressed)
			{
			  // Already on the list, so remove it.
			  MainWindow->numScriptKeysPressed--;
			  for (int j = i; j < MainWindow->numScriptKeysPressed;
			      j++)
			    {
			      MainWindow->scriptKeysPressed[j].whenPressed =
				  MainWindow->scriptKeysPressed[j + 1].whenPressed;
			      MainWindow->scriptKeysPressed[j].button =
				  MainWindow->scriptKeysPressed[j + 1].button;
			    }
			}
		      MainWindow->scriptKeysPressed[MainWindow->numScriptKeysPressed].whenPressed =
			  pulseCount;
		      MainWindow->scriptKeysPressed[MainWindow->numScriptKeysPressed].button =
			  button;
		      MainWindow->numScriptKeysPressed++;
		      button->Disable ();
		    }
		}
	      else if (MainWindow->scriptFileChannelNumber == 032)
		{
		  if ((MainWindow->scriptFileChannelValue & 020000) != 0)
		    MainWindow->ProButton->Enable ();
		  else
		    MainWindow->ProButton->Disable ();
		}
	      else
		ActOnIncomingIO ((unsigned char *) NULL);
	      MainWindow->scriptFileWaitUntil +=
		  MainWindow->scriptFileDifferentialTime;
	    }
	  else
	    return;
	}
    }
  // Try to connect to the server (yaAGC) if not already connected.
  if (ServerSocket == -1)
    {
      ServerSocket = CallSocket (Hostname, Portnum);
      if (ServerSocket != -1)
	printf ("yaDSKY is connected.\n");
    }
  if (ServerSocket != -1)
    {
      for (;;)
	{
	  i = recv (ServerSocket, (char *) &c, 1, MSG_NOSIGNAL);
	  if (i == -1)
	    {
	      // The conditions i==-1,errno==0 or 9 occur only on Win32,
	      // and I'm not sure exactly what they corresponds to---but
	      // empirically I find that ignoring them makes no difference
	      // to the operation of the program.
	      if (errno == EAGAIN || errno == 0 || errno == 9)
		i = 0;
	      else
		{
		  printf ("yaDSKY reports server error %d\n", errno);
		  close (ServerSocket);
		  ServerSocket = -1;
		  break;
		}
	    }
	  if (i == 0)
	    break;
	  // This (newer) code will accept any packet signature of the form
	  // 00 XX XX XX.
	  if (0 == (0xc0 & c))
	    PacketSize = 0;
	  if (PacketSize != 0 || (0xc0 & c) == 0)
	    {
	      Packet[PacketSize++] = c;
	      if (PacketSize >= 4)
		{
		  ActOnIncomingIO (Packet);
		  PacketSize = 0;
		}
	    }
	}
    }
}

// A function to overwrite one of the static bitmaps in the display, such as an 
// annunciator, with a replacement from a file.

void
MainFrame::ImageSet (wxStaticBitmap *StaticBitmap, wxString &Filename)
{
  wxString Dummy;
  wxBitmap Bitmap;
  if (HalfSize)
    Dummy = wxT ("h") + Filename;
  else
    Dummy = Filename;
  Bitmap = StaticBitmap->GetBitmap ();
  Bitmap.LoadFile (Dummy, wxBITMAP_TYPE_JPEG);
  StaticBitmap->SetBitmap (Bitmap);
}
void
MainFrame::ImageSet (wxStaticBitmap *StaticBitmap, char *Filename)
{
  wxString Dummy;
  Dummy = wxString::FromAscii (Filename);
  ImageSet (StaticBitmap, Dummy);
}
void
MainFrame::ImageSet (wxStaticBitmap *StaticBitmap, const char *Filename)
{
  ImageSet (StaticBitmap, (char *) Filename);
}
void
MainFrame::ImageSet (wxBitmapButton *BitmapButton, wxString &Filename)
{
  wxString Dummy;
  wxBitmap Bitmap;
  if (HalfSize)
    Dummy = wxT ("h") + Filename;
  else
    Dummy = Filename;
  Bitmap = BitmapButton->GetBitmapLabel ();
  Bitmap.LoadFile (Dummy, wxBITMAP_TYPE_JPEG);
  BitmapButton->SetBitmapLabel (Bitmap);
}
void
MainFrame::ImageSet (wxBitmapButton *BitmapButton, char *Filename)
{
  wxString Dummy;
  Dummy = wxString::FromAscii (Filename);
  ImageSet (BitmapButton, Dummy);
}
void
MainFrame::ImageSet (wxBitmapButton *BitmapButton, const char *Filename)
{
  ImageSet (BitmapButton, (char *) Filename);
}

//--------------------------------------------------------------------------------
// Function for acting on incoming channel i/o from yaAGC, and change any affected
// DSKY annunciators or 7-segment displays.  The Packet parameter
// is a string of 4 bytes, representing a channel i/o packet.  Refer to the
// Virtual AGC Technical Manual, "I/O Specifics" subheading of the "Developer
// Details" chapter.  (The widget parameter can be ANY widget.)

// Matches image widget filenames to channel 010 CCCCC and DDDDD fields.
static const char *SevenSegmentFilenames[32] =
  { "7Seg-0.jpg",
  NULL, NULL, "7Seg-3.jpg",
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
      "7Seg-15.jpg",
      NULL, NULL, NULL, "7Seg-19.jpg",
      NULL, "7Seg-21.jpg",
      NULL, NULL, NULL, "7Seg-25.jpg",
      NULL, "7Seg-27.jpg", "7Seg-28.jpg", "7Seg-29.jpg", "7Seg-30.jpg",
      "7Seg-31.jpg" };

static int IoErrorCount = 0, Last11 = 0;
static int R1Sign = 0, R2Sign = 0, R3Sign = 0;

void
TimerClass::ActOnIncomingIO (unsigned char *Packet)
{
  Ind_t *Indptr;
  int Channel, Value, uBit, i;
  if (Packet != NULL)
    {
      // Check to see if the message has a yaAGC signature.  If not,
      // ignore it.  The yaAGC signature is 00 01 10 11 in the
      // 2 most-significant bits of the packet's bytes.  We are
      // guaranteed that the first byte is signed 00, so we don't
      // need to check it.
      if (0x40 != (Packet[1] & 0xc0) || 0x80 != (Packet[2] & 0xc0)
	  || 0xc0 != (Packet[3] & 0xc0))
	return;
      if (ParseIoPacket (Packet, &Channel, &Value, &uBit))
	goto Error;
      // Save, in case we need to run a canned script and
      // restore the values afterward.
      if (uBit == 0)
	{
	  switch (Channel)
	    {
	    case 010:
	      int relay, relayValue;
	      relay = (Value >> 11) & 0x0F;
	      relayValue = Value & 03777;
	      if (MainWindow->last10[relay] != relayValue)
		{
		  MainWindow->last10[relay] = relayValue;
		  MainWindow->record (Channel, Value);
		}
	      break;
	    case 011:
	      if (MainWindow->last11 != Value)
		{
		  MainWindow->last11 = Value;
		  MainWindow->record (Channel, Value);
		}
	      break;
	    case 013:
	      if (MainWindow->last13 != Value)
		{
		  MainWindow->last13 = Value;
		  MainWindow->record (Channel, Value);
		}
	      break;
	    case 0163:
	      if (MainWindow->last163 != Value)
		{
		  MainWindow->last163 = Value;
		  MainWindow->record (Channel, Value);
		}
	      break;
	    default:
	      break;
	    }

	}

    }
  else
    {
      Channel = MainWindow->scriptFileChannelNumber;
      Value = MainWindow->scriptFileChannelValue;
      uBit = 0;
    }
  // Take care of all of the indicator lights.
  for (Indptr = Inds, i = 0; i < 14; Indptr++, i++)
    if (Indptr->Channel == Channel
	&& (!Indptr->Latched || ((Value & Indptr->RowMask) == Indptr->Row))
	&& Indptr->State != (Indptr->Bitmask & (Value ^ Indptr->Polarity)))
      {
	Indptr->State = (Indptr->Bitmask & (Value ^ Indptr->Polarity));
	if (Indptr->State == 0)
	  {
	    MainWindow->ImageSet (Indptr->Widget, Indptr->GraphicOff);
	    if (Indptr->Widget == MainWindow->OprErrAnnunciator)
	      MainWindow->CurrentOprErr = wxString::FromAscii (
		  Indptr->GraphicOff);
	    if (Indptr->Widget == MainWindow->KeyRelAnnunciator)
	      MainWindow->CurrentKeyRel = wxString::FromAscii (
		  Indptr->GraphicOff);
	  }
	else
	  {
	    MainWindow->ImageSet (Indptr->Widget, Indptr->GraphicOn);
	    if (Indptr->Widget == MainWindow->OprErrAnnunciator)
	      MainWindow->CurrentOprErr = wxString::FromAscii (
		  Indptr->GraphicOn);
	    if (Indptr->Widget == MainWindow->KeyRelAnnunciator)
	      MainWindow->CurrentKeyRel = wxString::FromAscii (
		  Indptr->GraphicOn);
	  }
      }
  // Now take care of everything that's left.  Only a few channels are of interest to the
  // DSKY as far as input is concerned.
  if (Channel == 010)
    {
      // 7-segment display management.
      wxStaticBitmap *Sign = NULL, *Left = NULL, *Right = NULL;
      int RSign = 0;
      // Set up the pointers to the widgets associated with this channel.
      switch (Value & 0x7800)
	{
	case 0x5800:	// AAAA=11D
	  Left = MainWindow->MD1Digit;
	  Right = MainWindow->MD2Digit;
	  break;
	case 0x5000:	// AAAA=10D
	  Left = MainWindow->VD1Digit;
	  Right = MainWindow->VD2Digit;
	  break;
	case 0x4800:	// AAAA=9
	  Left = MainWindow->ND1Digit;
	  Right = MainWindow->ND2Digit;
	  break;
	case 0x4000:	// AAAA=8
	  Right = MainWindow->R1D1Digit;
	  break;
	case 0x3800:	// AAAA=7
	  Sign = MainWindow->R1PlusMinus;
	  if (0 != (Value & 0x0400))
	    R1Sign |= 2;
	  else
	    R1Sign &= ~2;
	  RSign = R1Sign;
	  Left = MainWindow->R1D2Digit;
	  Right = MainWindow->R1D3Digit;
	  break;
	case 0x3000:	// AAAA=6
	  Sign = MainWindow->R1PlusMinus;
	  if (0 != (Value & 0x0400))
	    R1Sign |= 1;
	  else
	    R1Sign &= ~1;
	  RSign = R1Sign;
	  Left = MainWindow->R1D4Digit;
	  Right = MainWindow->R1D5Digit;
	  break;
	case 0x2800:	// AAAA=5
	  Sign = MainWindow->R2PlusMinus;
	  if (0 != (Value & 0x0400))
	    R2Sign |= 2;
	  else
	    R2Sign &= ~2;
	  RSign = R2Sign;
	  Left = MainWindow->R2D1Digit;
	  Right = MainWindow->R2D2Digit;
	  break;
	case 0x2000:	// AAAA=4
	  Sign = MainWindow->R2PlusMinus;
	  if (0 != (Value & 0x0400))
	    R2Sign |= 1;
	  else
	    R2Sign &= ~1;
	  RSign = R2Sign;
	  Left = MainWindow->R2D3Digit;
	  Right = MainWindow->R2D4Digit;
	  break;
	case 0x1800:	// AAAA=3
	  Left = MainWindow->R2D5Digit;
	  Right = MainWindow->R3D1Digit;
	  break;
	case 0x1000:	// AAAA=2
	  Sign = MainWindow->R3PlusMinus;
	  if (0 != (Value & 0x0400))
	    R3Sign |= 2;
	  else
	    R3Sign &= ~2;
	  RSign = R3Sign;
	  Left = MainWindow->R3D2Digit;
	  Right = MainWindow->R3D3Digit;
	  break;
	case 0x0800:	// AAAA=1
	  Sign = MainWindow->R3PlusMinus;
	  if (0 != (Value & 0x0400))
	    R3Sign |= 1;
	  else
	    R3Sign &= ~1;
	  RSign = R3Sign;
	  Left = MainWindow->R3D4Digit;
	  Right = MainWindow->R3D5Digit;
	  break;
	default:
	  goto Error;
	}
      // Write the sign.
      if (Sign != NULL)
	{
	  // + has priority if both are set
	  if (0 != (RSign & 2))
	    MainWindow->ImageSet (Sign, "PlusOn.jpg");
	  else if (0 != (RSign & 1))
	    MainWindow->ImageSet (Sign, "MinusOn.jpg");
	  else
	    MainWindow->ImageSet (Sign, "PlusMinusOff.jpg");
	}
      // Write the left digit.
      if (Left != NULL)
	{
	  int i;
	  i = (Value >> 5) & 0x1F;
	  if (SevenSegmentFilenames[i] == NULL)
	    goto Error;
	  if (Left == MainWindow->VD1Digit)
	    MainWindow->CurrentVD1 = wxString::FromAscii (
		SevenSegmentFilenames[i]);
	  else if (Left == MainWindow->ND1Digit)
	    MainWindow->CurrentND1 = wxString::FromAscii (
		SevenSegmentFilenames[i]);
	  MainWindow->ImageSet (Left, SevenSegmentFilenames[i]);
	}
      // Write the right digit.
      if (Right != NULL)
	{
	  int i;
	  i = Value & 0x1F;
	  if (SevenSegmentFilenames[i] == NULL)
	    goto Error;
	  if (Right == MainWindow->VD2Digit)
	    MainWindow->CurrentVD2 = wxString::FromAscii (
		SevenSegmentFilenames[i]);
	  else if (Right == MainWindow->ND2Digit)
	    MainWindow->CurrentND2 = wxString::FromAscii (
		SevenSegmentFilenames[i]);
	  MainWindow->ImageSet (Right, SevenSegmentFilenames[i]);
	}
    }
  else if (Channel == 011)
    {
      int i;
      // Here are appropriate Luminary 131 actions for various discrete
      // annunciations.
      if ((Value & 2) != (Last11 & 2))
	{
	  if (0 == (Value & 2))
	    MainWindow->ImageSet (MainWindow->CompActyAnnunciator,
				  "CompActyOff.jpg");
	  else
	    MainWindow->ImageSet (MainWindow->CompActyAnnunciator,
				  "CompActyOn.jpg");
	}

      Last11 = Value;
    }
  else if (Channel == 0163)
    {
      // Handle Verb/Noun flashing via the fake V/N flash channel 163
      if (Value & DSKY_VN_FLASH)
	{
	  MainWindow->ImageSet (MainWindow->VD1Digit, MainWindow->CurrentBlank);
	  MainWindow->ImageSet (MainWindow->VD2Digit, MainWindow->CurrentBlank);
	  MainWindow->ImageSet (MainWindow->ND1Digit, MainWindow->CurrentBlank);
	  MainWindow->ImageSet (MainWindow->ND2Digit, MainWindow->CurrentBlank);
	}
      else
	{
	  MainWindow->ImageSet (MainWindow->VD1Digit, MainWindow->CurrentVD1);
	  MainWindow->ImageSet (MainWindow->VD2Digit, MainWindow->CurrentVD2);
	  MainWindow->ImageSet (MainWindow->ND1Digit, MainWindow->CurrentND1);
	  MainWindow->ImageSet (MainWindow->ND2Digit, MainWindow->CurrentND2);
	}
    }
  return;
  Error: IoErrorCount++;
}

//--------------------------------------------------------------------------------
// A nice little function to output a keycode (except PRO) to yaAGC.

void
MainFrame::OutputKeycode (int Keycode)
{
  unsigned char Packet[4];
  int j;
  if (scriptFileOpen)
    return;
  record (015, Keycode);
  if (ServerSocket != -1)
    {
      if (TestUplink)
	{
	  // In this case, we communicate keycodes to the AGC via the digital
	  // uplink rather than through the normal DSKY input channel.
	  Keycode &= 037;
	  Keycode |= ((Keycode << 10) | ((Keycode ^ 037) << 5));
	  FormIoPacket (0173, Keycode, Packet);
	}
      else
	FormIoPacket (015, Keycode, Packet);
      j = send (ServerSocket, (const char *) Packet, 4, MSG_NOSIGNAL);
      if (j == SOCKET_ERROR && SOCKET_BROKEN)
	{
	  close (ServerSocket);
	  ServerSocket = -1;
	}
    }
}

void
MainFrame::record (int channel, int value)
{
  if (recordingFileOpen)
    {
      long now = scriptFileStopWatch.Time ();
      recordingFile.AddLine (
	  wxString::Format (wxT ("%ld %o %o"), now - recordingLastTime,
			    channel, value));
      recordingFile.Write();
      recordingLastTime = now;
    }

}

//--------------------------------------------------------------------------------
// ... and a similar function for outputting the PRO-key status to yaAGC.

void
MainFrame::OutputPro (int OffOn)
{
  unsigned char Packet[8];
  int j;
  if (scriptFileOpen)
    return;
  record (032, OffOn ? 020000 : 0);
  if (ServerSocket != -1)
    {
      // First, create the mask which will tell the CPU to only pay attention to
      // bit 14 of the channel (032).
      FormIoPacket (0432, 020000, Packet);
      // Next, generate the data itself.
      if (OffOn)
	OffOn = 020000;
      FormIoPacket (032, OffOn, &Packet[4]);
      // And, send it all.
      j = send (ServerSocket, (const char *) Packet, 8, MSG_NOSIGNAL);
      if (j == SOCKET_ERROR && SOCKET_BROKEN)
	{
	  close (ServerSocket);
	  ServerSocket = -1;
	}
    }
}

//--------------------------------------------------------------------------------
// Parses the configuration file.

void
xpm2jpg (char *s)
{
  char *ss;
  while (NULL != (ss = strstr (s, ".xpm")))
    {
      ss[1] = 'j';
      ss[2] = 'p';
      ss[3] = 'g';
    }
}

int
MainFrame::ParseCfg (wxString &Filename)
{
  Ind_t *Indptr;
  char s[129], *ss, s1[1024], s2[129], s3[129];
  int i, RetVal = 1, IndNum, BitNum, Polarity, Channel, Latched, RowMask, Row;
  FILE *Cfg = NULL;
  strcpy (s, Filename.char_str ());
  Cfg = rfopen (s, "r");
  if (Cfg == NULL)
    {
      printf ("The specified --cfg file does not exist.\n");
      goto Error;
    }
  s[sizeof(s) - 1] = 0;
  while (NULL != fgets (s, sizeof(s) - 1, Cfg))
    {
      // Trim off the trailing \n to make it easier to print error messages.
      for (ss = s; *ss; ss++)
	if (*ss == '\n' || *ss == '\r')
	  {
	    *ss = 0;
	    break;
	  }
      if (!strncmp (s, "DEBUG ", 6))
	continue;
      if (!strcmp (s, "LMSIM"))
	{
	  CmOrLm = 0;
	  continue;
	}
      if (!strcmp (s, "CMSIM"))
	{
	  CmOrLm = 1;
	  continue;
	}
      if (1 == sscanf (s, "PROKEY %s", s2))
	{
	  xpm2jpg (s2);
	  // Look up the widget for the PRO key, and change its graphic.
	  sprintf (s1, "%s%s", "", s2);
	  ImageSet (iLastButton, s1);
	  continue;
	}
      if (3 == sscanf (s, "IND %o %s %s", &IndNum, s2, s3))
	{
	  xpm2jpg (s2);
	  xpm2jpg (s3);
	  if (IndNum >= 011 && IndNum <= 017)
	    IndNum -= 011;
	  else if (IndNum >= 021 && IndNum <= 027)
	    IndNum += 7 - 021;
	  else
	    {
	      printf ("Indicator must be 11-17 or 21-27 in \"%s\".\n", s);
	      goto Error;
	    }
	  // Need a better way (or SOME way) to check here for string overflow.
	  sprintf (s1, "%s%s", "", s2);
	  Inds[IndNum].GraphicOn = (char *) malloc (strlen (s1) + 1);
	  if (Inds[IndNum].GraphicOn == NULL)
	    {
	      printf ("Out of memory.\n");
	      goto Error;
	    }
	  strcpy ((char *) Inds[IndNum].GraphicOn, s1);
	  sprintf (s1, "%s%s", "", s3);
	  Inds[IndNum].GraphicOff = (char *) malloc (strlen (s1) + 1);
	  if (Inds[IndNum].GraphicOff == NULL)
	    {
	      printf ("Out of memory.\n");
	      goto Error;
	    }
	  strcpy ((char *) Inds[IndNum].GraphicOff, s1);
	  if (NULL != strstr (s2, "KeyRel") || NULL != strstr (s3, "KeyRel"))
	    {
	      KeyRelAnnunciator = Inds[IndNum].Widget;
	      CurrentKeyRel = BlankKeyRel = wxString::FromAscii (
		  Inds[IndNum].GraphicOff);
	    }
	  if (NULL != strstr (s2, "OprErr") || NULL != strstr (s3, "OprErr"))
	    {
	      OprErrAnnunciator = Inds[IndNum].Widget;
	      CurrentOprErr = BlankOprErr = wxString::FromAscii (
		  Inds[IndNum].GraphicOff);
	    }
	  continue;
	}
      i = sscanf (s, "CHAN %o %o %d %d %o %o", &IndNum, &Channel, &BitNum,
		  &Polarity, &RowMask, &Row);
      if (i == 4 || i == 6)
	{
	  if (i == 4)
	    Latched = Row = RowMask = 0;
	  else
	    Latched = 1;
	  if (IndNum >= 011 && IndNum <= 017)
	    IndNum -= 011;
	  else if (IndNum >= 021 && IndNum <= 027)
	    IndNum += 7 - 021;
	  else
	    {
	      printf ("Indicator must be 11-17 or 21-27 in \"%s\".\n", s);
	      goto Error;
	    }
	  if (Channel < 0 || Channel > 255)
	    {
	      printf (
		  "The channel-number must be in the range 0-255 in \"%s\".\n",
		  s);
	      goto Error;
	    }
	  if (BitNum < 1 || BitNum > 15)
	    {
	      printf ("The bit-number must be in the range 1-15 in \"%s\".\n",
		      s);
	      goto Error;
	    }
	  if (Polarity != 0 && Polarity != 1)
	    {
	      printf ("Polarity must be 0 or 1 in \"%s\".\n", s);
	      goto Error;
	    }
	  BitNum--;
	  Inds[IndNum].Channel = Channel;
	  Inds[IndNum].Bitmask = (1 << BitNum);
	  Inds[IndNum].Polarity = (Polarity << BitNum);
	  Inds[IndNum].Latched = Latched;
	  Inds[IndNum].RowMask = RowMask;
	  Inds[IndNum].Row = Row;
	  continue;
	}
      for (ss = s; isspace (*ss); ss++)
	;
      if (*ss != 0 && *ss != '#')
	{
	  printf ("Input line not recognized: \"%s\".\n", s);
	  goto Error;
	}
    }
  // Update all of the indicator legends.  
  for (Indptr = Inds, i = 0; i < 14; Indptr++, i++)
    ImageSet (Indptr->Widget, Indptr->GraphicOff);
  RetVal = 0;
  Error: if (Cfg != NULL)
    fclose (Cfg);
  return (RetVal);
}

// The following function was adapted from the normal constructor.  It is called only at the point in the
// startup sequence where it has noted that the --half-size switch has been used, and it is called to
// replace the already-created but not-yet-displayed main window to use smaller graphics.
void
MainFrame::HalveTheWindow (void)
{
  int ButtonSize;
  if (HalfSize)
    ButtonSize = 40;
  else
    ButtonSize = 75;
  ImageSet (bitmap_5, "FrameVerticalL.jpg");
  ImageSet (bitmap_6_copy, "FrameHorizontal.jpg");
  ImageSet (Annunciator11, "UplinkActyOff.jpg");
  ImageSet (Annunciator21, "UplinkActyOff.jpg");
  ImageSet (Annunciator12, "UplinkActyOff.jpg");
  ImageSet (Annunciator22, "UplinkActyOff.jpg");
  ImageSet (Annunciator13, "UplinkActyOff.jpg");
  ImageSet (Annunciator23, "UplinkActyOff.jpg");
  ImageSet (Annunciator14, "UplinkActyOff.jpg");
  ImageSet (Annunciator24, "UplinkActyOff.jpg");
  ImageSet (Annunciator15, "UplinkActyOff.jpg");
  ImageSet (Annunciator25, "UplinkActyOff.jpg");
  ImageSet (Annunciator16, "UplinkActyOff.jpg");
  ImageSet (Annunciator26, "UplinkActyOff.jpg");
  ImageSet (Annunciator17, "UplinkActyOff.jpg");
  ImageSet (Annunciator27, "UplinkActyOff.jpg");
  ImageSet (bitmap_6, "FrameHorizontal.jpg");
  ImageSet (bitmap_5_copy, "FrameVerticalL.jpg");
  ImageSet (bitmap_5_copy_1, "FrameVerticalR.jpg");
  ImageSet (bitmap_6_copy_copy, "FrameHorizontal.jpg");
  ImageSet (CompActyAnnunciator, "CompActyOff.jpg");
  ImageSet (ModeAnnunciator, "rProgOn.jpg");
  ImageSet (MD1Digit, "7Seg-0.jpg");
  ImageSet (MD2Digit, "7Seg-0.jpg");
  ImageSet (VerbAnnunciator, "VerbOn.jpg");
  ImageSet (VD1Digit, "7Seg-0.jpg");
  ImageSet (VD2Digit, "7Seg-0.jpg");
  ImageSet (NounAnnunciator, "NounOn.jpg");
  ImageSet (ND1Digit, "7Seg-0.jpg");
  ImageSet (ND2Digit, "7Seg-0.jpg");
  ImageSet (bitmap_2_copy_1, "SeparatorOn.jpg");
  ImageSet (R1PlusMinus, "PlusMinusOff.jpg");
  ImageSet (R1D1Digit, "7Seg-0.jpg");
  ImageSet (R1D2Digit, "7Seg-0.jpg");
  ImageSet (R1D3Digit, "7Seg-0.jpg");
  ImageSet (R1D4Digit, "7Seg-0.jpg");
  ImageSet (R1D5Digit, "7Seg-0.jpg");
  ImageSet (bitmap_2_copy, "SeparatorOn.jpg");
  ImageSet (R2PlusMinus, "PlusMinusOff.jpg");
  ImageSet (R2D1Digit, "7Seg-0.jpg");
  ImageSet (R2D2Digit, "7Seg-0.jpg");
  ImageSet (R2D3Digit, "7Seg-0.jpg");
  ImageSet (R2D4Digit, "7Seg-0.jpg");
  ImageSet (R2D5Digit, "7Seg-0.jpg");
  ImageSet (bitmap_2, "SeparatorOn.jpg");
  ImageSet (R3PlusMinus, "PlusMinusOff.jpg");
  ImageSet (R3D1Digit, "7Seg-0.jpg");
  ImageSet (R3D2Digit, "7Seg-0.jpg");
  ImageSet (R3D3Digit, "7Seg-0.jpg");
  ImageSet (R3D4Digit, "7Seg-0.jpg");
  ImageSet (R3D5Digit, "7Seg-0.jpg");
  ImageSet (bitmap_6_copy_copy_copy, "FrameHorizontal.jpg");
  ImageSet (bitmap_5_copy_2, "FrameVerticalR.jpg");
  ImageSet (VerbButton, "VerbUp.jpg");
  ImageSet (NounButton, "NounUp.jpg");
  ImageSet (PlusButton, "PlusUp.jpg");
  ImageSet (MinusButton, "MinusUp.jpg");
  ImageSet (ZeroButton, "0Up.jpg");
  ImageSet (SevenButton, "7Up.jpg");
  ImageSet (FourButton, "4Up.jpg");
  ImageSet (OneButton, "1Up.jpg");
  ImageSet (EightButton, "8Up.jpg");
  ImageSet (FiveButton, "5Up.jpg");
  ImageSet (TwoButton, "2Up.jpg");
  ImageSet (NineButton, "9Up.jpg");
  ImageSet (SixButton, "6Up.jpg");
  ImageSet (ThreeButton, "3Up.jpg");
  ImageSet (ClrButton, "ClrUp.jpg");
  ImageSet (ProButton, "ProUp.jpg");
  ImageSet (KeyRelButton, "KeyRelUp.jpg");
  ImageSet (EntrButton, "EntrUp.jpg");
  ImageSet (RsetButton, "RsetUp.jpg");
  VerbButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  NounButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  PlusButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  MinusButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  ZeroButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  SevenButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  FourButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  OneButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  EightButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  FiveButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  TwoButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  NineButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  SixButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  ThreeButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  ClrButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  ProButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  KeyRelButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  EntrButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  RsetButton->SetMinSize (wxSize (ButtonSize, ButtonSize));
  Fit ();
}

// this is for the "presentation" feature:  the function checks the buffer 
// being accumulated from the keypad against the set of patterns read at 
// power-up from the optional DSKY2.matches file.  If there is a match, then
// the associated command (in the PC's native operating system) is performed.
void
MainFrame::MatchCheck (void)
{
  int i;
  for (i = 0; i < NumMatches; i++)
    if (Match.IsSameAs (*Matches[i].Pattern))
      wxExecute (*Matches[i].Command, wxEXEC_ASYNC);
}

back to top