//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "IOIRMain.h"
#include "KeyEdit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "JvHidControllerClass"
#pragma resource "*.dfm"
TMainForm *MainForm;
//---------------------------------------------------------------------------
  char *AddressNames[32] =
    {
     "TV1",
     "TV2",
     "Teletext",
     "Video",
     "LV1",
     "VCR1",
     "VCR2",
     "Experimental",
     "Sat1",
     "Camera",
     "Sat2",
     "11",
     "CDV",
     "Camcorder",
     "14",
     "15",
     "Pre-amp1",
     "Tuner",
     "Recorder1",
     "Pre-amp2",
     "CD Player",
     "Phono",
     "SatA",
     "Recorder2",
     "24",
     "25",
     "CDR",
     "27",
     "28",
     "Lighting1",
     "Lighting2",
     "Phone"
    };
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

// untangle the RC5 data and return an identifying value

DWORD ComputeData(TIOWarriorIRInputReport *Report)
{
  // only 6 bits meaningful
  Report->Command &= 0x3F;
  // move the inverted /C6 from Address to Command
  Report->Command = Report->Command | ((!Report->Address) & 0x40);
  // only 5 bits are address
  Report->Address &= 0x1F;
  // the combined bytes now describe a key on the IR remote
  return((Report->Address << 8) | Report->Command);
}
//---------------------------------------------------------------------------

// send a string of chars as if coming from keyboard
// only a..z, A..Z and 0..9 for simplicity

void SendKeycode(TListItem *Item)
{
  int I;
  AnsiString S;
  char B;

  S = Item->SubItems->Strings[2];
  for(I = 1; I <= S.Length(); I++)
  {
    B = S[I];
    if(B >= 'A' && B <= 'Z')
    {
      keybd_event(VK_SHIFT, 0, 0, 0);
      keybd_event(B,  0, 0, 0);
      keybd_event(B,  0, KEYEVENTF_KEYUP, 0);
      keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
    }
    else
    if(B >= 'a' && B <= 'z')
    {
      B -= 'a' - 'A';
      keybd_event(B, 0, 0, 0);
      keybd_event(B, 0, KEYEVENTF_KEYUP, 0);
    }
    else
    if(B >= 'a' && B <= 'z')
    {
      keybd_event(B, 0, 0, 0);
      keybd_event(B, 0, KEYEVENTF_KEYUP, 0);
    }
  }
}
//---------------------------------------------------------------------------

bool __stdcall FindIOWarrior(TJvHidDevice *HidDev)
{
  // the IO-Warrior shows up as two devices
  // we want access to the IO-Warrior device for the IO pins
  // the other one with a InputReportByteLength of 8 is for access to
  // the optional LCD module
  return (HidDev->Attributes.VendorID == cCodeMercenariesVID &&
    HidDev->Attributes.ProductID == cIOWarriorPID2 &&
    HidDev->Caps.InputReportByteLength == 8);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::HidCtlDeviceChange(TObject *Sender)
{
  int I;
  unsigned int BytesWritten;
  TIOWarriorIROutputReport IOWarriorOutputReport;

  // Free the device object if it has been unplugged
  if(IOWarrior != NULL && !IOWarrior->IsPluggedIn)
    FreeAndNil(&IOWarrior);

  // if no IO-Warrior in use yet then search for one
  if(IOWarrior == NULL)
    if(HidCtl->CheckOutByCallback(IOWarrior, FindIOWarrior))
    {
      // enable IR mode
      memset(&IOWarriorOutputReport, 0, sizeof(IOWarriorOutputReport));
      IOWarriorOutputReport.ReportID  = 0x0C;
      IOWarriorOutputReport.IOData[0] = 0x01;
      IOWarrior->WriteFile(&IOWarriorOutputReport, sizeof(IOWarriorOutputReport), BytesWritten);
    }

  // update the controls on the form
  UpdateControls();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FormActivate(TObject *Sender)
{
  // the first OnDeviceChange could not access the controls
  // so it is repeated here
  UpdateControls();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::UpdateControls(void)
{
  if(IOWarriorDetected != NULL)
  {
    Description->Enabled = IOWarrior != NULL;
    if(IOWarrior != NULL)
      IOWarriorDetected->Caption = "IO-Warrior with IR is plugged in";
    else
      IOWarriorDetected->Caption = "No IO-Warrior with IR is plugged in";
  }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::HidCtlDeviceData(TJvHidDevice *HidDev,
      BYTE ReportID, const Pointer Data, WORD Size)
{
  int I;
  DWORD Val;
  int FoundAt;
  AnsiString S;
  TListItem *Item;
  TIOWarriorIRInputReport IOWarriorInputReport;

  IOWarriorInputReport = *(TIOWarriorIRInputReport *) Data;
  if(ReportID == cIRCommand)
  {
    // extract data payload from report
    Val = ComputeData(&IOWarriorInputReport);

    // search if code already in list
    FoundAt = -1;
    for(I = 0; I < CodeList->Items->Count; I++)
      if(Val == (DWORD) (CodeList->Items->Item[I]->Data))
      {
        FoundAt = I;
        break;
      };

    if(FoundAt == -1)
    {
      // code not found so add it to list
      Item = CodeList->Items->Add();
      Item->Caption = AddressNames[IOWarriorInputReport.Address];
      Item->SubItems->Add(S.sprintf("%d", IOWarriorInputReport.Command));
      Item->SubItems->Add("--");
      Item->SubItems->Add("");
      Item->Data = (void *) Val;
    }
    else
    {
      // code found so send the assigned keys
      Item = CodeList->Items->Item[FoundAt];
      CodeList->ItemIndex = FoundAt;
      SendKeycode(Item);
    }
  }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::CodeListDblClick(TObject *Sender)
{
  TListItem *Item;
  TKeyEditForm *KeyEditForm;

  Item = NULL;
  if(CodeList->ItemIndex >= 0)
    Item = CodeList->Items->Item[CodeList->ItemIndex];
  if(Item != NULL)
  {
     KeyEditForm = new TKeyEditForm(this);
     KeyEditForm->Address->Caption = Item->Caption;
     KeyEditForm->Value->Caption   = Item->SubItems->Strings[0];
     KeyEditForm->Name->Text       = Item->SubItems->Strings[1];
     KeyEditForm->Keys->Text       = Item->SubItems->Strings[2];
     if(KeyEditForm->ShowModal() == mrOk)
     {
       Item->SubItems->Strings[1] = KeyEditForm->Name->Text;
       Item->SubItems->Strings[2] = KeyEditForm->Keys->Text;
     }
     delete KeyEditForm;
  }
}
//---------------------------------------------------------------------------

