unit frmConfigureUnt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls, ComCtrls, Grids, ImgList, AtariControls;

type
  TfrmConfigure = class(TForm)
    pcUser: TPageControl;
    btnOk: TBitBtn;
    tbKeyboard: TTabSheet;
    tbMouse: TTabSheet;
    tbDigital: TTabSheet;
    rbMouseXAxis: TRadioButton;
    rbMouseLeft: TRadioButton;
    rbMouseRight: TRadioButton;
    rbMouseMiddle: TRadioButton;
    sgKeyboard: TStringGrid;
    ImageList1: TImageList;
    ImageList2: TImageList;
    ImageList3: TImageList;
    rbMouseYAxis: TRadioButton;
    cbController: TComboBox;
    sgProps: TStringGrid;
    sgController: TStringGrid;
    Timer1: TTimer;
    Label1: TLabel;
    procedure btnOkClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure sgKeyboardDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgKeyboardSelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure pcUserChange(Sender: TObject);
    procedure pcControllerChange(Sender: TObject);
    procedure sgKeyboardClick(Sender: TObject);
    procedure rbMouseXAxisClick(Sender: TObject);
    procedure rbMouseYAxisClick(Sender: TObject);
    procedure rbMouseLeftClick(Sender: TObject);
    procedure rbMouseRightClick(Sender: TObject);
    procedure rbMouseMiddleClick(Sender: TObject);
    procedure cbControllerChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sgPropsDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgPropsSelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure sgControllerDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgControllerClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    Updating  : Boolean;
    KbdIntf   : TKeyboardInterface;
    MouseIntf : TMouseInterface;
    OtherIntf : TDigitalInterface;
    Cap       : TCapability;
    OldKeys   : Array[0..255] Of Boolean;
    StrWid    : Integer;
    Procedure GetBaseRowCol(Var Row,Col: Integer);
    Procedure LoadControllerInfo;
    Procedure LoadDigitalInfo;
    Function  AxisOnly: Boolean;
    Procedure SetGridWidths;
    Procedure ChangeCapability;
    Function  CannotChange: Boolean;
    Procedure SetKeyboardSize;
  public
    { Public declarations }
  end;

var
  frmConfigure: TfrmConfigure;

implementation

Uses HandTIA, frmMainunt;

Const
  CellWidth : Array[0..6,0..22] Of Integer =
  ((1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0),
   (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
   (1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1),
   (1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1),
   (1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,0,0,0,0,1,1,1,0),
   (1,1,1,1,1,1,1,1,1,1,1,3,1,2,0,0,1,0,0,1,1,1,1),
   (1,1,1,7,1,2,3,4,5,6,1,1,1,1,0,1,1,1,0,2,1,1,0));

  CellHeight : Array[0..6,0..22] Of Integer =
  ((1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0),
   (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
   (1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1),
   (1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,2),
   (1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1),
   (1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,1,1,1,2),
   (1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,0,1,0,1,1));

  CellText : Array[0..6,0..22] Of String =
  (('Esc',  'F1', 'F2', 'F3',   'F4','F5','F6','F7','F8','F9','F10','F11',  'F12',  '',    '','Print','Scrl','Pause','','',   '', '', ''),
   ('',     '',   '',   '',     '',  '',  '',  '',  '',  '',  '',   '',     '',     '',    '','',     '',    '',     '','',   '', '', ''),
   ('`',    '1',  '2',  '3',    '4', '5', '6', '7', '8', '9', '0',  '-',    '=',    'BkSp','','Ins',  'Home','PgUp', '','Num','/','*','-'),
   ('Tab',  'Q',  'W',  'E',    'R', 'T', 'Y', 'U', 'I', 'O', 'P',  '[',    ']',    '\',   '','Del',  'End', 'PgDn', '','7',  '8','9','+'),
   ('Caps', 'A',  'S',  'D',    'F', 'G', 'H', 'J', 'K', 'L', ';',  '''',   'Enter','',    '','',     '',    '',     '','4',  '5','6',''),
   ('Shift','Z',  'X',  'C',    'V', 'B', 'N', 'M', ',', '.', '/',  'Shift','',     '',    '','',     'Up',  '',     '','1',  '2','3','Enter'),
   ('Ctrl', 'Win','Alt','Space','',  '',  '',  '',  '',  '',  'Alt','Win',  'Menu', 'Ctrl','','Lf',   'Dn',  'Rt',   '','0',  '', '.',''));

  CellChangeable : Array[0..6,0..22] Of Boolean =
  ((False,True, False,False,False,False,False,False,True, True, False,True, True, True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, False,False,True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True),
   (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True));

  CellScanCode : Array[0..6,0..22] Of Word =
  (($0001,$003B,$003C,$003D,$003E,$003F,$0040,$0041,$0042,$0043,$0044,$0057,$0058,0,    0,    $00B7,$0046,$0077,0,    0,    0,    0,    0),
   (0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0),
   ($0029,$0002,$0003,$0004,$0005,$0006,$0007,$0008,$0009,$000A,$000B,$000C,$000D,$000E,0,    $00D2,$00C7,$00C9,0,    $0045,$00B5,$0037,$004A),
   ($000F,$0010,$0011,$0012,$0013,$0014,$0015,$0016,$0017,$0018,$0019,$001A,$001B,$002B,0,    $00D3,$00CF,$00D1,0,    $0047,$0048,$0049,$004E),
   ($003A,$001E,$001F,$0020,$0021,$0022,$0023,$0024,$0025,$0026,$0027,$0028,$001C,0,    0,    0,    0,    0,    0,    $004B,$004C,$004D,0),
   ($002A,$002C,$002D,$002E,$002F,$0030,$0031,$0032,$0033,$0034,$0035,$0036,0,    0,    0,    0,    $00C8,0,    0,    $004F,$0050,$0051,$001C),
   ($001D,$00DB,$0038,$0039,0,    0,    0,    0,    0,    0,    $00B8,$00DC,$00DD,$009D,0,    $00CB,$00D0,$00CD,0,    $0052,0,    $0053,0));

  PropsCells : Array[0..24,0..5] Of String =
  (('Console switches', 'Joysticks',    'Paddles',            'Driving',          'Keyboard/VTP',    'Booster-grip'),
   ('Select',           'Joy 1 left',   'Paddle 1 left',      'Driving 1 left',   'Kbd 1 key 1',     'Trigger button'),
   ('Reset',            'Joy 1 right',  'Paddle 1 right',     'Driving 1 right',  'Kbd 1 key 2',     'Thumb button'),
   ('Color/B-W',        'Joy 1 up',     'Paddle 1 button',    'Driving 1 button', 'Kbd 1 key 3',     ''),
   ('Power',            'Joy 1 down',   'Paddle 2 left',      'Driving 2 left',   'Kbd 1 key 4',     ''),
   ('Player 1 diff.',   'Joy 1 button', 'Paddle 2 right',     'Driving 2 right',  'Kbd 1 key 5',     ''),
   ('Player 2 diff.',   'Joy 2 left',   'Paddle 2 button',    'Driving 2 button', 'Kbd 1 key 6',     ''),
   ('',                 'Joy 2 right',  'Paddle 3 left',      '',                 'Kbd 1 key 7',     ''),
   ('',                 'Joy 2 up',     'Paddle 3 right',     '',                 'Kbd 1 key 8',     ''),
   ('',                 'Joy 2 down',   'Paddle 3 button',    '',                 'Kbd 1 key 9',     ''),
   ('',                 'Joy 2 button', 'Paddle 4 left',      '',                 'Kbd 1 key *',     ''),
   ('',                 '',             'Paddle 4 right',     '',                 'Kbd 1 key 1',     ''),
   ('',                 '',             'Paddle 4 button',    '',                 'Kbd 1 key #',     ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 1', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 2', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 3', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 4', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 5', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 6', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 7', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 8', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 9', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key *', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key 0', ''),
   ('',                 '',             '',                   '',                 'Kbd 2/VTP key #', ''));

  PropsCount : Array[0..5] Of Integer = (6,10,12,6,24,2);

  PropsCaps : Array[0..23,0..5] Of LongInt =
  ((ifSelect,  ifJoy1Left,  ifPaddle1Left,  ifDriving1Left,  ifKB1_1,     ifCBSBtn1),
   (ifReset,   ifJoy1Right, ifPaddle1Right, ifDriving1Right, ifKB1_2,     ifCBSBtn2),
   (ifColorBW, ifJoy1Up,    ifPaddle1Btn,   ifDriving1Btn,   ifKB1_3,     0),
   (ifPower,   ifJoy1Down,  ifPaddle2Left,  ifDriving2Left,  ifKB1_4,     0),
   (ifDiff1,   ifJoy1Btn,   ifPaddle2Right, ifDriving2Right, ifKB1_5,     0),
   (ifDiff2,   ifJoy2Left,  ifPaddle2Btn,   ifDriving2Btn,   ifKB1_6,     0),
   (0,         ifJoy2Right, ifPaddle3Left,  0,               ifKB1_7,     0),
   (0,         ifJoy2Up,    ifPaddle3Right, 0,               ifKB1_8,     0),
   (0,         ifJoy2Down,  ifPaddle3Btn,   0,               ifKB1_9,     0),
   (0,         ifJoy2Btn,   ifPaddle4Left,  0,               ifKB1_Star,  0),
   (0,         0,           ifPaddle4Right, 0,               ifKB1_0,     0),
   (0,         0,           ifPaddle4Btn,   0,               ifKB1_Pound, 0),
   (0,         0,           0,              0,               ifKB2_1,     0),
   (0,         0,           0,              0,               ifKB2_2,     0),
   (0,         0,           0,              0,               ifKB2_3,     0),
   (0,         0,           0,              0,               ifKB2_4,     0),
   (0,         0,           0,              0,               ifKB2_5,     0),
   (0,         0,           0,              0,               ifKB2_6,     0),
   (0,         0,           0,              0,               ifKB2_7,     0),
   (0,         0,           0,              0,               ifKB2_8,     0),
   (0,         0,           0,              0,               ifKB2_9,     0),
   (0,         0,           0,              0,               ifKB2_Star,  0),
   (0,         0,           0,              0,               ifKB2_0,     0),
   (0,         0,           0,              0,               ifKB2_Pound, 0));

  DigitalCells : Array[0..4] Of String = ('Buttons','Digital axes','Hats','Throttles','Analog axes');

{$R *.DFM}

procedure TfrmConfigure.btnOkClick(Sender: TObject);
Var
  I    : Integer;
  Intf : TInterface;

begin
  // Locate the interfaces

  I := 0;
  While I < InterfaceHandler.Stack.Count Do
  Begin
    Intf := TInterface(InterfaceHandler.Stack.Objects[I]);
    If Intf.Name = 'Keyboard' Then KbdIntf.CopyTo(Intf)
    Else If Intf.Name = 'Mouse' Then MouseIntf.CopyTo(Intf)
    Else OtherIntf.CopyTo(Intf);
    Inc(I);
  End; // While
  Close;
end;

procedure TfrmConfigure.FormShow(Sender: TObject);
Var
  I,J  : Integer;
  Intf : TInterface;

Begin

  // Locate the interfaces

  I := 0;
  While I < InterfaceHandler.Stack.Count Do
  Begin
    Intf := TInterface(InterfaceHandler.Stack.Objects[I]);
    If Intf.Name = 'Keyboard' Then Intf.CopyTo(KbdIntf)
    Else If Intf.Name = 'Mouse' Then Intf.CopyTo(MouseIntf)
    Else Intf.CopyTo(OtherIntf);
    Inc(I);
  End; // While
  sgController.DefaultRowHeight := Canvas.TextHeight('Mg') + 6;
  sgProps.DefaultRowHeight := Canvas.TextHeight('Mg') + 6;
  SetGridWidths;
  Updating := False;
  For I := 0 To 6 Do
   For J := 0 To sgKeyboard.ColCount - 1 Do sgKeyboard.Cells[J,I] := CellText[I,J];
  SetKeyboardSize;
  pcUserChange(Self);
  pcControllerChange(Self);
  Timer1.Enabled := True;
  FillChar(OldKeys,SizeOf(OldKeys),#0);
end;

Procedure TfrmConfigure.SetKeyboardSize;
Var
  I,W,H : Integer;
  Ok    : Boolean;

Begin
  W := Trunc((sgKeyboard.Width - 8) / 22.5);
  H := Trunc(W * (40 / 45));
  If (H * 6.25) + 8 > sgKeyboard.Height Then
  Begin
    H := Trunc((sgKeyboard.Height - 8) / 6.25);
    W := Trunc(H * (45 / 40));
  End;

  // Resize text font in keyboard grid

  If W < StrWid + 4 Then
  Begin
    sgKeyboard.Canvas.Font.Name := 'Arial';
    sgKeyboard.Canvas.Font.Size := 1;
    I                           := 1;
    Repeat
      sgKeyboard.Canvas.Font.Size := I + 1;
      Ok := (sgKeyboard.Canvas.TextWidth('Pause') < W - 2);
      If Ok Then Inc(I);
    Until Not Ok;
    sgKeyboard.Canvas.Font.Size := I;
  End
  Else
  Begin
    sgKeyboard.Canvas.Font.Name := 'MS Sans Serif';
    sgKeyboard.Canvas.Font.Size := 8;
  End;

  I := Round(H * 6.25 + 8);
  sgKeyboard.Height           := I;
  sgKeyboard.DefaultColWidth  := W;
  sgKeyboard.DefaultRowHeight := H;
  I := H Div 4;
  If I < 1 Then I := 1;
  sgKeyboard.ColWidths[14] := I;
  sgKeyboard.ColWidths[18] := I;
  sgKeyboard.RowHeights[1] := I;
  pcUser.Repaint;
End; // TfrmConfigure.SetKeyboardSize

procedure TfrmConfigure.sgKeyboardDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
Var
  W       : Integer;
  H       : Integer;
  CF,CB   : TColor;
  Row,Col : Integer;
  I       : Integer;
  X,Y     : Integer;

begin
  Row := ARow;
  Col := ACol;
  GetBaseRowCol(Row,Col);
  If (CellWidth[ARow,ACol]  > 0) Or
     (CellHeight[ARow,ACol] > 0) Then
  Begin
    W := Rect.Right  - Rect.Left;
    H := Rect.Bottom - Rect.Top;
    Dec(Rect.Left,(ACol - Col) * W);
    Dec(Rect.Top, (ARow - Row) * H);
    ARow := Row;
    ACol := Col;

    Rect.Right  := Rect.Left + CellWidth[ARow,ACol]  * W;
    Rect.Bottom := Rect.Top  + CellHeight[ARow,ACol] * H;

    If CellChangeable[ARow,ACol] Then
    Begin
      If (ARow = sgKeyboard.Row) And (ACol = sgKeyboard.Col) Then
      Begin
        CF := clHighlightText;
        CB := clHighlight;
      End
      Else
      Begin
        CF := clBlack;
        CB := sgKeyboard.Color;
      End;
    End
    Else
    Begin
      If (ARow = sgKeyboard.Row) And (ACol = sgKeyboard.Col) Then
      Begin
        CF := clHighlightText;
        CB := clHighlight;
      End
      Else
      Begin
        CF := clBlack;
        CB := sgKeyboard.FixedColor;
      End;
    End;

    If (CellText[ARow,ACol] <> '') And
       (KbdIntf <> Nil)            And
       KbdIntf.UsedCapability(KbdIntf.KeyCap[CellScanCode[ARow,ACol]]) And
       (CB <> clHighlight) Then
    Begin
      If CellChangeable[ARow,ACol]
       Then CB := $00E0FFE0
       Else CB := $00C0F0C0;
    End;

    // Draw outline

    sgKeyboard.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgKeyboard.Canvas.Pen.Color := clbtnHighlight;
    sgKeyboard.Canvas.LineTo(Rect.Left,Rect.Top);
    sgKeyboard.Canvas.LineTo(Rect.Right - 1,Rect.Top);
    sgKeyboard.Canvas.Pen.Color := clBtnShadow;
    sgKeyboard.Canvas.LineTo(Rect.Right - 1,Rect.Bottom - 1);
    sgKeyboard.Canvas.LineTo(Rect.Left,Rect.Bottom - 1);

    // Fill center

    sgKeyboard.Canvas.Pen.Color   := CB;
    sgKeyboard.Canvas.Brush.Color := CB;
    sgKeyboard.Canvas.Brush.Style := bsSolid;
    sgKeyboard.Canvas.Font.Color  := CF;
    sgKeyboard.Canvas.Rectangle(Rect.Left + 1,Rect.Top + 1,Rect.Right - 1,Rect.Bottom - 1);

    // Draw text

    sgKeyboard.Canvas.TextOut(Rect.Left + 2,Rect.Top + 2,CellText[ARow,ACol]);

    For I := 0 To 255 Do
    Begin
      If OldKeys[I] Then
      Begin
        If CellScanCode[ARow,ACol] = I Then
        Begin
          sgKeyboard.Canvas.Pen.Color   := clRed;
          sgKeyboard.Canvas.Brush.Color := clRed;
          X := Rect.Left + ((Rect.Right  - Rect.Left) Div 2);
          Y := Rect.Top  + ((Rect.Bottom - Rect.Top)  Div 2);
          sgKeyboard.Canvas.Ellipse(X - 2,Y - 2,X + 2,Y + 2);
        End;
      End;
    End; // For I
  End
  Else
  Begin
    sgKeyboard.Canvas.Pen.Color   := sgKeyboard.Color;
    sgKeyboard.Canvas.Brush.Color := sgKeyboard.Color;
    sgKeyboard.Canvas.Rectangle(Rect.Left,Rect.Top,Rect.Right,Rect.Bottom);
  End;
end; // TfrmConfigure.sgKeyboardDrawCell

procedure TfrmConfigure.sgKeyboardSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
Var C,R,C1,R1,C2,R2: Integer;
begin
  If Not Updating Then
  Begin

    // Paint the old one

    C  := sgKeyboard.Col;
    R  := sgKeyboard.Row;
    C1 := ACol;
    R1 := ARow;
    GetBaseRowCol(R,C);
    GetBaseRowCol(R1,C1);

    CanSelect := False;  // We will control selection
    Updating  := True;   // Prevent recursion

    // Cycle through the old key cells if necessary to force repaint

    If (R1 <> R) Or (C1 <> C) Then
     For C2 := 0 To CellWidth[R,C] - 1 Do
      For R2 := 0 To CellHeight[R,C] - 1 Do
      Begin
        sgKeyboard.Row := R + R2;
        sgKeyboard.Col := C + C2;
        sgKeyboard.Invalidate;
        sgKeyboard.Repaint;
      End; // For R2

    // Set to the new key cell

    If (R1 <> sgKeyboard.Row) Or (C1 <> sgKeyboard.Col) Then
    Begin
      sgKeyboard.Row := R1;
      sgKeyboard.Col := C1;
      sgKeyboard.Invalidate;
      sgKeyboard.Repaint;
    End;
    Updating := False;
  End
  Else CanSelect := True;
end;

Procedure TfrmConfigure.GetBaseRowCol(Var Row,Col: Integer);
Var C,R: Integer;
Begin
  If (CellWidth[Row,Col]  > 0) Or
     (CellHeight[Row,Col] > 0) Then
  Begin
    If CellText[Row,Col] = '' Then
    Begin
      C   := Col - CellWidth[Row,Col];
      R   := Row - CellHeight[Row,Col];
      Row := R;
      Col := C;
    End;
  End;
End; { TfrmConfigure.GetBaseRowCol }

procedure TfrmConfigure.pcUserChange(Sender: TObject);
Var
  NumCons  : Integer;
  I,J      : LongInt;
  SlotMap  : LongInt;
  Vendor   : String;
  Product  : String;

begin
  If pcUser.ActivePage = tbDigital Then
  Begin
    If OtherIntf <> Nil Then
    Begin
      I := 0;
      Repeat
        OtherIntf.RefreshControllers;
        SlotMap := OtherIntf.GetSlotMap;
        Inc(I);
      Until (I > 31) Or (SlotMap <> 0);

      { Find out how many controllers are connected }

      J       := 1;
      NumCons := 0;
      For I := 0 To 31 Do
      Begin
        If (SlotMap And J) <> 0 Then Inc(NumCons);
        J := J Shl 1;
      End; { For I }

      { Initialize the menu and get the controller information }

      cbController.Clear;
      If NumCons > 0 Then
      Begin
        J := 1;
        For I := 0 To 31 Do
        Begin
          If (SlotMap And J) <> 0 Then
          Begin
            Vendor  := OtherIntf.GetVendorName(I);
            Product := OtherIntf.GetProductName(I);
            While (Vendor <> '') And (Vendor[1] < ' ') Do
             Vendor := Copy(Vendor,2,Length(Vendor) - 1);
            While (Product <> '') And (Product[1] < ' ') Do
             Product := Copy(Product,2,Length(Product) - 1);
            cbController.Items.Add(Vendor + ' ' + Product);
          End;
          J := J Shl 1;
        End; { For I }
        cbController.ItemIndex := 0;
        LoadDigitalInfo;
      End;
    End;
  End;
  LoadControllerInfo;  
end;

procedure TfrmConfigure.pcControllerChange(Sender: TObject);
begin
  LoadControllerInfo;
end;

Procedure TfrmConfigure.LoadControllerInfo;
Var
  Intf  : TInterface;
  I     : Integer;
  R,C   : Integer;

Begin
  If pcUser.ActivePage = tbKeyboard Then Intf := KbdIntf Else
   If pcUser.ActivePage = tbMouse    Then Intf := MouseIntf Else Intf := OtherIntf;
  If Intf <> Nil Then
  Begin
    Cap.A := 0;
    Cap.B := 0;
    If Intf.Name = 'Keyboard' Then
    Begin
      R := sgKeyboard.Row;
      C := sgKeyboard.Col;
      If (R >= 0) And (C >= 0) And (CellText[R,C] <> '') Then
      Begin
        Cap := TKeyboardInterface(Intf).KeyCap[CellScanCode[R,C]];
      End;
    End
    Else If Intf.Name = 'Mouse' Then
    Begin
           If rbMouseXAxis.Checked  Then Cap := TMouseInterface(Intf).MouseX.Cap
      Else If rbMouseYAxis.Checked  Then Cap := TMouseInterface(Intf).MouseY.Cap
      Else If rbMouseLeft.Checked   Then Cap := TMouseInterface(Intf).MouseBtn[1]
      Else If rbMouseRight.Checked  Then Cap := TMouseInterface(Intf).MouseBtn[2]
      Else If rbMouseMiddle.Checked Then Cap := TMouseInterface(Intf).MouseBtn[3];
    End
    Else
    Begin
      I := cbController.ItemIndex;
      If I >= 0 Then
      Begin
        If (sgController.Row >= 1) And (sgController.Col >= 0) Then
        Begin
          Case sgController.Col Of
            0: Cap := TDigitalInterface(Intf).Cap[I + 1].Btn[sgController.Row];
            1: Cap := TDigitalInterface(Intf).Cap[I + 1].Axis[sgController.Row];
            2: Cap := TDigitalInterface(Intf).Cap[I + 1].Hat[sgController.Row];
            3: Cap := TDigitalInterface(Intf).Cap[I + 1].Thr[sgController.Row].Cap;
            4: Cap := TDigitalInterface(Intf).Cap[I + 1].Ana[sgController.Row].Cap;
          End; { Case }
        End;
      End;
    End;
    sgProps.Invalidate;
    sgProps.Repaint;
  End;
End; // TfrmConfigure.LoadControllerInfo

Procedure TfrmConfigure.ChangeCapability;
Var
  Intf  : TInterface;
  I     : Integer;
  R,C   : Integer;

Begin
  If pcUser.ActivePage = tbKeyboard Then Intf := KbdIntf Else
   If pcUser.ActivePage = tbMouse    Then Intf := MouseIntf Else Intf := OtherIntf;
  If Intf <> Nil Then
  Begin
    If Intf.Name = 'Keyboard' Then
    Begin
      R := sgKeyboard.Row;
      C := sgKeyboard.Col;
      If (R >= 0) And (C >= 0) And (CellText[R,C] <> '') Then
      Begin
        TKeyboardInterface(Intf).KeyCap[CellScanCode[R,C]] := Cap;
      End;
    End
    Else If Intf.Name = 'Mouse' Then
    Begin
           If rbMouseXAxis.Checked  Then TMouseInterface(Intf).MouseX.Cap  := Cap
      Else If rbMouseYAxis.Checked  Then TMouseInterface(Intf).MouseY.Cap  := Cap
      Else If rbMouseLeft.Checked   Then TMouseInterface(Intf).MouseBtn[1] := Cap
      Else If rbMouseRight.Checked  Then TMouseInterface(Intf).MouseBtn[2] := Cap
      Else If rbMouseMiddle.Checked Then TMouseInterface(Intf).MouseBtn[3] := Cap;
    End
    Else
    Begin
      I := cbController.ItemIndex;
      If I >= 0 Then
      Begin
        If (sgController.Row >= 1) And (sgController.Col >= 0) Then
        Begin
          Case sgController.Col Of
            0: TDigitalInterface(Intf).Cap[I + 1].Btn[sgController.Row]     := Cap;
            1: TDigitalInterface(Intf).Cap[I + 1].Axis[sgController.Row]    := Cap;
            2: TDigitalInterface(Intf).Cap[I + 1].Hat[sgController.Row]     := Cap;
            3: TDigitalInterface(Intf).Cap[I + 1].Thr[sgController.Row].Cap := Cap;
            4: TDigitalInterface(Intf).Cap[I + 1].Ana[sgController.Row].Cap := Cap;
          End; { Case }
        End;
      End;
    End;
  End;
End; // TfrmConfigure.ChangeCapability

procedure TfrmConfigure.sgKeyboardClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.rbMouseXAxisClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.rbMouseYAxisClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.rbMouseLeftClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.rbMouseRightClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.rbMouseMiddleClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.cbControllerChange(Sender: TObject);
begin
  LoadDigitalInfo;
  LoadControllerInfo;
end;

Procedure TfrmConfigure.LoadDigitalInfo;
Var
  Con,I : Integer;
  Cap   : TCapability;
  Info  : TAtariControls;

Begin
  If (OtherIntf <> Nil) And (cbController.ItemIndex >= 0) Then
  Begin
    Con := cbController.ItemIndex + 1;
    OtherIntf.GetControllerInfo(Cap,Info);
    I := 0;
    If OtherIntf.Cap[Con].NumBtns > I Then I := OtherIntf.Cap[Con].NumBtns;
    If OtherIntf.Cap[Con].NumAxes > I Then I := OtherIntf.Cap[Con].NumAxes;
    If OtherIntf.Cap[Con].NumHats > I Then I := OtherIntf.Cap[Con].NumHats;
    If OtherIntf.Cap[Con].NumThrs > I Then I := OtherIntf.Cap[Con].NumThrs;
    If OtherIntf.Cap[Con].NumAnas > I Then I := OtherIntf.Cap[Con].NumAnas;
    sgController.RowCount := I + 1;

    // Load digital controller string grid

    For I := 0 To 4 Do sgController.Cells[0,I] := DigitalCells[I];
    For I := 1 To OtherIntf.Cap[Con].NumBtns Do sgController.Cells[I,0] := 'Button '       + IntToStr(I);
    For I := 1 To OtherIntf.Cap[Con].NumAxes Do sgController.Cells[I,1] := 'Digital axis ' + IntToStr(I);
    For I := 1 To OtherIntf.Cap[Con].NumHats Do sgController.Cells[I,2] := 'Hat '          + IntToStr(I);
    For I := 1 To OtherIntf.Cap[Con].NumThrs Do sgController.Cells[I,3] := 'Throttle '     + IntToStr(I);
    For I := 1 To OtherIntf.Cap[Con].NumAnas Do sgController.Cells[I,4] := 'Analog axis '  + IntToStr(I);
  End;
End; // TfrmConfigure.LoadDigitalInfo

procedure TfrmConfigure.FormCreate(Sender: TObject);
Var I,J: Integer;
begin
  KbdIntf   := TKeyboardInterface.Create;
  MouseIntf := TMouseInterface.Create;
  OtherIntf := TDigitalInterface.Create('Digital');
  Caption   := 'PCAE ' + Version;
  Cap.A     := 0;
  Cap.B     := 0;

  // Load properties string grid

  For I := 0 To 5 Do
   For J := 0 To 24 Do sgProps.Cells[J,I] := PropsCells[J,I];

  // Load digital controller string grid

  For I := 0 To 4 Do sgController.Cells[0,I] := DigitalCells[I];
  StrWid := Canvas.TextWidth('Pause');
end;

procedure TfrmConfigure.sgPropsDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
Var
  L   : LongInt;
  C   : TColor;
  Y   : Integer;
  Img : TIcon;

begin
  If ACol In [0,4] Then L := Cap.B Else L := Cap.A;
  Y := Rect.Top + ((Rect.Bottom - Rect.Top - sgProps.Canvas.TextHeight('Mg')) Div 2);
  If ARow = 0 Then
  Begin
    sgProps.Canvas.Pen.Color   := clBtnHighlight;
    sgProps.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgProps.Canvas.LineTo(Rect.Left,Rect.Top);
    sgProps.Canvas.LineTo(Rect.Right,Rect.Top);
    sgProps.Canvas.Pen.Color   := clBtnShadow;
    sgProps.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgProps.Canvas.LineTo(Rect.Right - 1,Rect.Bottom - 1);
    sgProps.Canvas.LineTo(Rect.Right - 1,Rect.Top);
    sgProps.Canvas.Pen.Color   := sgProps.FixedColor;
    sgProps.Canvas.Brush.Color := sgProps.FixedColor;
    sgProps.Canvas.Rectangle(Rect.Left + 1,Rect.Top + 1,Rect.Right,Rect.Bottom);

    Img := TIcon.Create;
    ImageList3.GetIcon(ACol,Img);
    sgProps.Canvas.Draw(Rect.Left + 2,Rect.Top + 2,Img);
    Img.Free;

    sgProps.Canvas.Font.Color := clBlack;
    sgProps.Canvas.TextOut(Rect.Left + 28,Y,sgProps.Cells[ARow,ACol]);
  End
  Else
  Begin
    If L And PropsCaps[ARow - 1,ACol] <> 0
     Then C := $00FFE0E0
     Else C := Color;
    sgProps.Canvas.Pen.Color   := C;
    sgProps.Canvas.Brush.Color := C;
    sgProps.Canvas.Rectangle(Rect);
    If AxisOnly And
       ((PropsCaps[ARow - 1,ACol] And (imPaddleAxis + imDrivingAxis + imJoyAxis) = 0) Or
        (ACol In [0,4]))
     Then sgProps.Canvas.Font.Color  := clGray
     Else sgProps.Canvas.Font.Color  := clBlack;
    sgProps.Canvas.TextOut(Rect.Left + 2,Y,sgProps.Cells[ARow,ACol]);
  End;
end;

Function TfrmConfigure.AxisOnly: Boolean;
Begin
  AxisOnly := ((pcUser.ActivePage = tbMouse) And
               (rbMouseXAxis.Checked Or rbMouseYAxis.Checked)) Or
              ((pcUser.ActivePage = tbDigital) And
               (sgController.Col <> 0));
End; // TfrmConfigure.AxisOnly

Function TfrmConfigure.CannotChange: Boolean;
Begin
  CannotChange := (pcUser.ActivePage = tbKeyboard) And
                  Not CellChangeable[sgKeyboard.Row,sgKeyboard.Col];
End; // TfrmConfigure.CannotChange

procedure TfrmConfigure.sgPropsSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
Var
  I   : Integer;
  J,L : LongInt;
  C   : LongInt;

begin
  CanSelect := True;
  If ARow >= 1 Then
  Begin
    If ACol In [0,4] Then L := Cap.B Else L := Cap.A;
    C := PropsCaps[ARow - 1,ACol];
    If CannotChange Then
    Begin
      CanSelect := False;
      Exit;
    End;
    If AxisOnly Then
    Begin
      If (Not (ACol In [0,4])) And
         ((C And (imPaddleAxis + imDrivingAxis + imJoyAxis)) <> 0) Then
      Begin
        If (C And imPaddle1Axis) <> 0 Then C := imPaddle1Axis Else
         If (C And imPaddle2Axis) <> 0 Then C := imPaddle2Axis Else
          If (C And imPaddle3Axis) <> 0 Then C := imPaddle3Axis Else
           If (C And imPaddle4Axis) <> 0 Then C := imPaddle4Axis Else
            If (C And imDriving1Axis) <> 0 Then C := imDriving1Axis Else
             If (C And imDriving2Axis) <> 0 Then C := imDriving2Axis Else
              If (C And imJoy1X) <> 0 Then C := imJoy1X Else
               If (C And imJoy1Y) <> 0 Then C := imJoy1Y Else
                If (C And imJoy2X) <> 0 Then C := imJoy2X Else
                 If (C And imJoy2Y) <> 0 Then C := imJoy2Y;
      End
      Else
      Begin
        CanSelect := False;
        Exit;
      End;
    End;

    J := 0;
    For I := 0 To PropsCount[ACol] - 1 Do J := J Or PropsCaps[I,ACol];
    If (L And C) <> 0
     Then L := L Xor C
     Else L := (L And (Not J)) Or C;
    If ACol In [0,4]
     Then Cap.B := L
     Else Cap.A := L;
    ChangeCapability; 
    sgProps.Invalidate;
    sgProps.Repaint;
  End;
end;

procedure TfrmConfigure.sgControllerDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
Var
  CF,CB : TColor;
  I     : Integer;
  Y     : Integer;
  X1,Y1 : Integer;
  Img   : TIcon;
  W     : Integer;
  W1    : Integer;

begin
  Y  := Rect.Top + ((Rect.Bottom - Rect.Top - sgController.Canvas.TextHeight('Mg')) Div 2);
  X1 := Rect.Left + 10;
  Y1 := Rect.Top + ((Rect.Bottom - Rect.Top) Div 2);
  If ARow = 0 Then
  Begin
    sgController.Canvas.Pen.Color   := clBtnHighlight;
    sgController.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgController.Canvas.LineTo(Rect.Left,Rect.Top);
    sgController.Canvas.LineTo(Rect.Right,Rect.Top);
    sgController.Canvas.Pen.Color   := clBtnShadow;
    sgController.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgController.Canvas.LineTo(Rect.Right - 1,Rect.Bottom - 1);
    sgController.Canvas.LineTo(Rect.Right - 1,Rect.Top);
    sgController.Canvas.Pen.Color   := sgController.FixedColor;
    sgController.Canvas.Brush.Color := sgController.FixedColor;
    sgController.Canvas.Rectangle(Rect.Left + 1,Rect.Top + 1,Rect.Right,Rect.Bottom);

    Img := TIcon.Create;
    ImageList2.GetIcon(ACol,Img);
    sgController.Canvas.Draw(Rect.Left + 2,Rect.Top + 2,Img);
    Img.Free;

    sgController.Canvas.Font.Color := clBlack;
    sgController.Canvas.TextOut(Rect.Left + 28,Y,sgController.Cells[ARow,ACol]);
  End
  Else
  Begin
    If gdSelected In State Then
    Begin
      CF := clHighlightText;
      CB := clHighlight;
    End
    Else
    Begin
      CF := clBlack;
      CB := Color;
    End;
    sgController.Canvas.Pen.Color   := CB;
    sgController.Canvas.Brush.Color := CB;
    sgController.Canvas.Font.Color  := CF;
//    sgController.Canvas.Rectangle(Rect);
    I := cbController.ItemIndex;
    If (OtherIntf <> Nil) And (I >= 0) Then
    Begin
      Case ACol Of
        0: If ARow <= OtherIntf.Cap[I + 1].NumBtns Then
           Begin
             If OtherIntf.UsedCapability(OtherIntf.Cap[I + 1].Btn[ARow]) Then
             Begin
               If CB <> clHighlight Then CB := $00E0FFE0;
               sgController.Canvas.Pen.Color   := CB;
               sgController.Canvas.Brush.Color := CB;
             End;
             sgController.Canvas.Rectangle(Rect);
             If (OtherIntf.ContInfo[I + 1].Buttons And (1 Shl (ARow - 1))) <> 0 Then
             Begin
               sgController.Canvas.Pen.Color   := clRed;
               sgController.Canvas.Brush.Color := clRed;
               sgController.Canvas.Ellipse(X1 - 2,Y1 - 2,X1 + 2,Y1 + 2);
             End;
           End;
        1: Begin
             If ARow <= OtherIntf.Cap[I + 1].NumAxes Then
             Begin
               If OtherIntf.UsedCapability(OtherIntf.Cap[I + 1].Axis[ARow]) Then
               Begin
                 If CB <> clHighlight Then CB := $00E0FFE0;
                 sgController.Canvas.Pen.Color   := CB;
                 sgController.Canvas.Brush.Color := CB;
               End;
               sgController.Canvas.Rectangle(Rect);
               sgController.Canvas.Pen.Color   := clRed;
               sgController.Canvas.Brush.Color := clRed;
               W  := OtherIntf.ContInfo[I + 1].Axis[ARow];
               Inc(X1,8 * ((W - 10) Div 10));
               sgController.Canvas.Ellipse(X1 - 2,Y1 - 2,X1 + 2,Y1 + 2);
             End
             Else sgController.Canvas.Rectangle(Rect);
           End;
        2: Begin
             If ARow <= OtherIntf.Cap[I + 1].NumHats Then
             Begin
               If OtherIntf.UsedCapability(OtherIntf.Cap[I + 1].Hat[ARow]) Then
               Begin
                 If CB <> clHighlight Then CB := $00E0FFE0;
                 sgController.Canvas.Pen.Color   := CB;
                 sgController.Canvas.Brush.Color := CB;
               End;
               sgController.Canvas.Rectangle(Rect);
               sgController.Canvas.Pen.Color   := clRed;
               sgController.Canvas.Brush.Color := clRed;
               W  := OtherIntf.ContInfo[I + 1].Hat[ARow];
               Inc(X1,8 * ((W - 10) Div 10));
               sgController.Canvas.Ellipse(X1 - 2,Y1 - 2,X1 + 2,Y1 + 2);
             End
             Else sgController.Canvas.Rectangle(Rect);
           End;
        3: Begin
             If ARow <= OtherIntf.Cap[I + 1].NumThrs Then
             Begin
               If OtherIntf.UsedCapability(OtherIntf.Cap[I + 1].Thr[ARow].Cap) Then
               Begin
                 If CB <> clHighlight Then CB := $00E0FFE0;
                 sgController.Canvas.Pen.Color   := CB;
                 sgController.Canvas.Brush.Color := CB;
               End;
               sgController.Canvas.Rectangle(Rect);
               W1 := OtherIntf.Cap[I + 1].Thr[ARow].Max - OtherIntf.Cap[I + 1].Thr[ARow].Min;
               If W1 > 0 Then
               Begin
                 W := OtherIntf.ContInfo[I + 1].Throttle[ARow];
                 sgController.Canvas.Pen.Color   := clRed;
                 sgController.Canvas.Brush.Color := clRed;
                 Inc(X1,Round((W - OtherIntf.Cap[I + 1].Thr[ARow].Min - W1 Div 2) * (8 / W1)));
                 sgController.Canvas.Ellipse(X1 - 2,Y1 - 2,X1 + 2,Y1 + 2);
               End;
             End
             Else sgController.Canvas.Rectangle(Rect);
           End;
        4: Begin
             If ARow <= OtherIntf.Cap[I + 1].NumAnas Then
             Begin
               If OtherIntf.UsedCapability(OtherIntf.Cap[I + 1].Ana[ARow].Cap) Then
               Begin
                 If CB <> clHighlight Then CB := $00E0FFE0;
                 sgController.Canvas.Pen.Color   := CB;
                 sgController.Canvas.Brush.Color := CB;
               End;
               sgController.Canvas.Rectangle(Rect);
               W1 := OtherIntf.Cap[I + 1].Ana[ARow].Max - OtherIntf.Cap[I + 1].Ana[ARow].Min;
               If W1 > 0 Then
               Begin
                 W := OtherIntf.ContInfo[I + 1].Analog[ARow];
                 sgController.Canvas.Pen.Color   := clRed;
                 sgController.Canvas.Brush.Color := clRed;
                 Inc(X1,Round((W - OtherIntf.Cap[I + 1].Ana[ARow].Min - W1 Div 2) * (8 / W1)));
                 sgController.Canvas.Ellipse(X1 - 2,Y1 - 2,X1 + 2,Y1 + 2);
               End;
             End
             Else sgController.Canvas.Rectangle(Rect);
           End;
      End; { Case }
    End;
    sgController.Canvas.Pen.Color   := CB;
    sgController.Canvas.Brush.Color := CB;
    sgController.Canvas.TextOut(Rect.Left + 20,Y,sgController.Cells[ARow,ACol]);
  End;
end;

procedure TfrmConfigure.sgControllerClick(Sender: TObject);
begin
  LoadControllerInfo;
end;

procedure TfrmConfigure.FormResize(Sender: TObject);
begin
  pcUser.Width   := Width  - 24;
  sgProps.Width  := Width  - 24;
  sgProps.Height := Height - sgProps.Top - 75;
  btnOk.Top      := Height - 68;
  btnOk.Left     := Width  - 89;
  SetGridWidths;
  SetKeyboardSize;
  sgKeyboard.Invalidate;
  sgKeyboard.Refresh;
end;

Procedure TfrmConfigure.SetGridWidths;
Var I,J,S: Integer;
Begin
  S := GetSystemMetrics(SM_CXHSCROLL);
  sgController.DefaultColWidth := (sgController.Width - S) Div sgController.ColCount;
  sgProps.DefaultColWidth      := (sgProps.Width - S)      Div sgProps.ColCount;

  J := 0;
  For I := 0 To sgController.ColCount - 2 Do Inc(J,sgController.ColWidths[I] + sgController.GridLineWidth);
  sgController.ColWidths[sgController.ColCount - 1] := sgController.Width - J - S - 4;

  J := 0;
  For I := 0 To sgProps.ColCount - 2 Do Inc(J,sgProps.ColWidths[I] + sgProps.GridLineWidth);
  sgProps.ColWidths[sgProps.ColCount - 1] := sgProps.Width - J - S - 4;
End; // TfrmConfigure.SetGridWidths

procedure TfrmConfigure.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Timer1.Enabled := False;
end;

procedure TfrmConfigure.Timer1Timer(Sender: TObject);
Var
  Cap      : TCapability;
  Info     : TAtariControls;
  ContInfo : Array[1..Max_Digital_Con] Of TDigitalInfoRec;
  Diff     : Boolean;
  I,J      : Integer;

begin
  If pcUser.ActivePage = tbKeyboard Then
  Begin
    If KbdIntf <> Nil Then
    Begin
      KbdIntf.GetControllerInfo(Cap,Info);
      I    := 0;
      Diff := False;
      While (I <= 255) And Not Diff Do
      Begin
        If Keys[I] <> OldKeys[I] Then Diff := True Else Inc(I);
      End; // While
      For I := 0 To 255 Do OldKeys[I] := Keys[I];
      If Diff Then
      Begin
        sgKeyboard.Invalidate;
        sgKeyboard.Repaint;
      End;
    End;
  End
  Else If pcUser.ActivePage = tbMouse Then
  Begin
//    If MouseIntf <> Nil Then MouseIntf.GetControllerInfo(Cap,Info);
  End
  Else
  Begin
    If OtherIntf <> Nil Then
    Begin
      For I := 1 To Max_Digital_Con Do ContInfo[I] := OtherIntf.ContInfo[I];
      OtherIntf.GetControllerInfo(Cap,Info);
      I    := 1;
      Diff := False;
      While (I <= Max_Digital_Con) And Not Diff Do
      Begin
        If ContInfo[I].Buttons <> OtherIntf.ContInfo[I].Buttons Then Diff := True Else
        Begin
          J := 1;
          While (J < Max_Digital_Axis) And Not Diff Do
          Begin
            If ContInfo[I].Axis[J] <> OtherIntf.ContInfo[I].Axis[J] Then Diff := True;
            Inc(J);
          End; // While

          J := 1;
          While (J < Max_Digital_Hat) And Not Diff Do
          Begin
            If ContInfo[I].Hat[J] <> OtherIntf.ContInfo[I].Hat[J] Then Diff := True;
            Inc(J);
          End; // While

          J := 1;
          While (J < Max_Digital_Thr) And Not Diff Do
          Begin
            If ContInfo[I].Throttle[J] <> OtherIntf.ContInfo[I].Throttle[J] Then Diff := True;
            Inc(J);
          End; // While

          J := 1;
          While (J < Max_Digital_Ana) And Not Diff Do
          Begin
            If ContInfo[I].Analog[J] <> OtherIntf.ContInfo[I].Analog[J] Then Diff := True;
            Inc(J);
          End; // While
        End;
        Inc(I);
      End; { While }
      If Diff Then
      Begin
        sgController.Invalidate;
        sgController.Repaint;
      End;  
    End;
  End;
end;

procedure TfrmConfigure.FormDestroy(Sender: TObject);
begin
  KbdIntf.Free;
  MouseIntf.Free;
  OtherIntf.Free;
end;

end.

// ----------------------------------------------------------------------
// PCAE and PCAEWin - PC Atari Emulator - Atari 2600 emulator
// Copyright (C) 2000 John Dullea
//
//  This program 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.
//
//  This program 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 this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------
