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

#include <vcl.h>
#pragma hdrstop

#include "uVKey.h"
#include "uData.h"
#include "DgHook.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "PBEdit"
#pragma resource "*.dfm"

TfrmVKey *frmVKey;
TfrmVKey *gVKey;
//---------------------------------------------------------------------------
#define TAB       0x02
#define CAPSLOCK  0x03
#define SHIFT     0x04
#define CTRL      0x05
#define BSPACE    0x06
#define ENTER     0x07
#define ALT       0x08
#define WINDOW    0x9
#define LEFT      0x0A
#define RIGHT     0x0B
#define UP        0x0C
#define DOWN      0x0D
#define ESC       0x0E
#define PUP       0x0F
#define PDN       0x10
#define HOME      0x11
#define END       0x12
#define INS       0x13
#define DEL       0x14
#define HANEN     0x15

TList *kList;
int pKeyWidth;
int pKeyHeight;

HHOOK             HMouseHook;
LRESULT CALLBACK  MouseHookProc(int Code, WPARAM wParam, LPARAM lParam);
void __fastcall   SendKey(KEYDEF *keydef);

HANDLE hLastAct;
//---------------------------------------------------------------------------
__fastcall TfrmVKey::TfrmVKey(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

__fastcall TfrmVKey::TfrmVKey(TComponent* Owner, HWND hWnd): TForm(Owner)
{
   gFocus = hWnd;
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::FormCreate(TObject *Sender)
{
   kList = new TList;

	//control row
//	AddKey(0x00,0x00,0); //signal row change
//	AddKey(0x00,ESC,10);
//	for(int fnkey = 0x70; fnkey < 0x7C; fnkey++)
//	{
//		AddKey(0x00,fnkey & 0xFF,10);
//	}
//	AddKey(0x00,INS,14);
//	AddKey(0x00,DEL,-10);

	//first row
	AddKey(0x00,0x00,1); //signal row change
	AddKey('`','~',10);
	AddKey('1','!',10);
	AddKey('2','@',10);
	AddKey('3','#',10);
	AddKey('4','$',10);
	AddKey('5','%',10);
	AddKey('6','^',10);
	AddKey('7','&',10);
	AddKey('8','*',10);
	AddKey('9','(',10);
	AddKey('0',')',10);
	AddKey('-','_',10);
	AddKey('=','+',10);
	AddKey(0x00,BSPACE,14); //backspace
//	AddKey(0x00,PUP,-12);

	//second row
	AddKey(0x00,0x00,2); //signal row change
	AddKey(0x00,TAB,14); //tab
	AddKey('q','Q',10);
	AddKey('w','W',10);
	AddKey('e','E',10);
	AddKey('r','R',10);
	AddKey('t','T',10);
	AddKey('y','Y',10);
	AddKey('u','U',10);
	AddKey('i','I',10);
	AddKey('o','O',10);
	AddKey('p','P',10);
	AddKey('[','{',10);
	AddKey(']','}',10);
	AddKey('\\','|',10);
//	AddKey(0x00,PDN,-12);

	//third row
	AddKey(0x00,0x00,3); //signal row change
	AddKey(0x00,CAPSLOCK,18); //caps lock
	AddKey('a','A',10);
	AddKey('s','S',10);
	AddKey('d','D',10);
	AddKey('f','F',10);
	AddKey('g','G',10);
	AddKey('h','H',10);
	AddKey('j','J',10);
	AddKey('k','K',10);
	AddKey('l','L',10);
	AddKey(';',':',10);
	AddKey('\'','\"',10);
	AddKey(0x00,ENTER,16); //enter
//	AddKey(0x00,HOME,-10);

	//fourth row
	AddKey(0x00,0x00,4); //signal row change
	AddKey(0x00,SHIFT,22); //shift
	AddKey('z','Z',10);
	AddKey('x','X',10);
	AddKey('c','C',10);
	AddKey('v','V',10);
	AddKey('b','B',10);
	AddKey('n','N',10);
	AddKey('m','M',10);
	AddKey(',','<',10);
	AddKey('.','>',10);
	AddKey('/','?',10);
	AddKey(0x00,SHIFT,22); //shift
//	AddKey(0x00,END,-10);

	//fifth row
	AddKey(0x00,0x00,5); //signal row change
	AddKey(0x00,CTRL,12); //ctrl
	AddKey(0x00,WINDOW,12); //window
	AddKey(0x00,ALT,12); //alt
	AddKey(' ',' ',60);
	AddKey(0x00,LEFT,12); //left
	AddKey(0x00,UP,12); //up
	AddKey(0x00,DOWN,12); //down
	AddKey(0x00,HANEN,12); //right
//	AddKey(0x00,WWW,-10); //http://WWW

   gVKey = this;
   CreateFileMap();
   SetData(tdRHandle, (int)Handle);
   HMouseHook =
    SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc, HInstance, GetCurrentThreadId());

   if(!SetWndHook()){
      ShowMessage("윈도우 훅 설치 실패");
   }
   if(!SetKeybdHook()){
      ShowMessage("키보드 훅 설치 실패");
   }

}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::FormActivate(TObject *Sender)
{
   CalcWidthHeight();
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::FormDestroy(TObject *Sender)
{
   kList->Clear();
   delete kList;
   if(!DeleteWndHook()){
      ShowMessage("윈도우 훅 제거 실패");
   }
   if(!DeleteKeybdHook()){
      ShowMessage("키보드 훅 제거 실패");
   }
   UnhookWindowsHookEx(HMouseHook);

   EraseFileMap();
   gVKey = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::AddKey(char pNormal, char pShifted, int pWidth)
{
   KEYDEF *key = new KEYDEF;
   key->cNormal   = pNormal;
   key->cShifted  = pShifted;
   key->cWidth    = pWidth;
   kList->Add(key);
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::CalcWidthHeight()
{
   pKeyWidth   = 0;
   pKeyHeight  = 0;
   KEYDEF *key;
	long totalWidth = 0;
	long longest = 0;
	long rows = 0;

   for(int i=0; i<kList->Count; i++){
      key = (KEYDEF *)kList->Items[i];
      if((key->cNormal == 0x00) && (key->cShifted == 0x00)){
         rows++;
         if(totalWidth > longest)
            longest = totalWidth;
         totalWidth = 0;
      }
      else
         totalWidth += abs(key->cWidth);
   }

   TRect rect = gVKey->ClientRect;
   pKeyHeight  = (rect.Height()) / rows;
   pKeyWidth   = (int)(((double)rect.Width()) / ((((double)(longest))/10)));
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::DrawKey(TCanvas *dc, TRect &rc, KEYDEF *key, bool bHilight)
{
   TRect tRc, tRc1;
   tRc   = TRect(rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1);
   tRc1  = TRect(rc.left + 3, rc.top + 3, rc.right - 3, rc.bottom - 3);
   if(bHilight){
      dc->Brush->Color = clLime;
      dc->FrameRect(tRc);
      dc->FrameRect(tRc1);
   }
   else{
      dc->Brush->Color = clLime;
      dc->FrameRect(tRc);
   }
   dc->Brush->Color = gVKey->Color;

   if(key->cNormal == 0x00){
      String label   = "";
      bool bSpecial  = false;
      if(key->cShifted > 0x6F) { // FUNCTION KEY
         int fkeynum = key->cShifted - 0x6F;
         label.sprintf("F%d", fkeynum);
      }
      else{
         switch (key->cShifted)
         {
           case TAB:
            label = "Clr";
            //label = "Tab->";
            break;
           case CAPSLOCK:
            label = "Caps";
            break;
           case SHIFT:
            label = "Shift";
            break;
           case CTRL:
            label = "Ctrl";
            break;
           case BSPACE:
            label = "<-Bspc";
            break;
           case ENTER:
            label = "Enter";
            break;
           case ALT:
            label = "Alt";
            break;
           case WINDOW:
            label = "Wnd";
            break;
           case ESC:
            label = "Esc";
            break;
           case HANEN:
            label = "한/영";
            break;
           default: break;
         }
      }
      if(!bSpecial){
         TSize tsz;
         tsz = dc->TextExtent(label);
         dc->TextOutA( ((rc.left + rc.right)/2) - (tsz.cx/2),
            ((rc.top + rc.bottom)/2) - (tsz.cy/2), label);
      }
   }
   else{
      if((key->cShifted >= 'A') && (key->cShifted <= 'Z')){
         TSize tsz;
         tsz = dc->TextExtent(key->cShifted);
         dc->TextOutA(
            ((tRc1.left + tRc1.right)/2) - (tsz.cx/2),
            ((tRc1.top + tRc1.bottom)/2) - (tsz.cy/2),
            key->cShifted);
      }
      else{
         TSize tsz;
         tsz = Canvas->TextExtent("M");
         dc->TextOutA(tRc1.left+2, tRc1.top+2, key->cShifted);
         dc->TextOutA(tRc1.right - (tsz.cx+2), tRc1.bottom - (tsz.cy+2), key->cNormal);
      }
   }
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::DrawKeyboard()
{
   TCanvas *dc = gVKey->Canvas;
   dc->Handle = gVKey->Canvas->Handle;
   TRect client = gVKey->ClientRect;
   HRGN  clipRgn;
   clipRgn = CreateRectRgnIndirect(&client);
   SetBkMode(clipRgn, TRANSPARENT);

   int x = 0;
   int y = -pKeyHeight;
   KEYDEF *key;
   nCurKeyState = DescribeKeyState();
   int state = nCurKeyState;

   for(int i=0; i<kList->Count; i++){
      key = (KEYDEF *)kList->Items[i];
      if((key->cNormal == 0x00) && (key->cShifted == 0x00)){
         x = 0;
         y += pKeyHeight;
      }
      else{
         int width = ((abs(key->cWidth) * pKeyWidth) / 10);
         TRect rc(x, y, x+width, y+pKeyHeight);
         x += width;
         if(key->cWidth < 0)
            rc.right = client.right;
         bool hilight = false;
         if(key->cNormal == 0x00){
            switch (key->cShifted)
            {
              case CAPSLOCK:
               if(state & 0x01)
                  hilight = true;
               break;
              case SHIFT:
               if(state & 0x02)
                  hilight = true;
               break;
              case CTRL:
               if(state & 0x04)
                  hilight = true;
               break;
              default: break;
            }
         }
         DrawKey(dc, rc, key, hilight);
      }
   }
}
//---------------------------------------------------------------------------
int __fastcall TfrmVKey::DescribeKeyState()
{
	int state = 0;
	short ks;
	ks = GetKeyState(VK_CAPITAL);
	if(ks & 0x000F) state += 0x01;
	ks = GetKeyState(VK_SHIFT);
	if(ks & 0xF000) state += 0x02;
	ks = GetKeyState(VK_CONTROL);
	if(ks & 0xF000) state += 0x04;
	return state;
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::FormPaint(TObject *Sender)
{
   DrawKeyboard();
}
//---------------------------------------------------------------------------

void __fastcall TfrmVKey::FormResize(TObject *Sender)
{
   CalcWidthHeight();
   Invalidate();
}
//---------------------------------------------------------------------------

void __fastcall TfrmVKey::FormMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
//   if(!m_bHanMode)
//      ReleaseFocus();
/*
   TRect client;
   client = TRect(this->ClientRect.left, this->ClientRect.top + pnlTop->Height,
      this->ClientRect.right, this->ClientRect.bottom);
   int x = 0;
   int y = -pKeyHeight+ pnlTop->Height;
   KEYDEF *key;
   for(int i=0; i<kList->Count; i++){
      key = (KEYDEF *)kList->Items[i];
      if((key->cNormal == 0x00) && (key->cShifted == 0x00)){
         x = 0;
         y += pKeyHeight;
      }
      else{
         int width = ((abs(key->cWidth) * pKeyWidth) / 10);
         TRect rc = TRect(x, y, x + width, y + pKeyHeight);
         if(key->cWidth < 0)
            rc.right = client.right;
         x += width;
         if(X >= (x-width) && X <= x && Y >= y && Y <= (y+pKeyHeight)){
            SendKey(key);
            break;
         }
      }
   }  */
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::FormMouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
   TCanvas *dc = gVKey->Canvas;
   dc->Handle = gVKey->Canvas->Handle;

   TRect client = gVKey->ClientRect;
   int x = 0;
   int y = -pKeyHeight;
   KEYDEF *key;
   for(int i=0; i<kList->Count; i++){
      key = (KEYDEF *)kList->Items[i];
      if((key->cNormal == 0x00) && (key->cShifted == 0x00)){
         x = 0;
         y += pKeyHeight;
      }
      else{
         int width = ((abs(key->cWidth) * pKeyWidth) / 10);
         TRect rc = TRect(x, y, x + width, y + pKeyHeight);
         if(key->cWidth < 0)
            rc.right = client.right;
         x += width;
         if(X >= (x-width) && X <= x && Y >= y && Y <= (y+pKeyHeight))
            DrawMouseOver(dc, rc, key, true);
         else
            DrawMouseOver(dc, rc, key, false);
      }
   }
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::DrawMouseOver(TCanvas *dc, TRect &rc, KEYDEF *key, bool bIsOver)
{
   TRect tRc, tRc1;
   tRc   = TRect(rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1);
   tRc1  = TRect(rc.left + 3, rc.top + 3, rc.right - 3, rc.bottom - 3);
   if(bIsOver){
      dc->Brush->Color = clYellow;
      dc->FrameRect(tRc);
      dc->FrameRect(tRc1);
   //   dc->FillRect(tRc);
   }
   else{
      dc->Brush->Color = clLime;
      dc->FrameRect(tRc);
      dc->Brush->Color = gVKey->Color;
      dc->FrameRect(tRc1);
   }
   dc->Brush->Color = gVKey->Color;
}
//---------------------------------------------------------------------------
void __fastcall SendKey(KEYDEF *keydef)
{
   if(keydef->cNormal == 0x00){
      int vk;
      bool uptoo = true;
      if(keydef->cShifted > 0x6F)
         vk = keydef->cShifted;
      else{
         switch (keydef->cShifted)
         {
           case TAB:
            //vk = VkKeyScan(0x09) & 0xFF;
      //      edtKeyVal->Text = ""; return;
            break;
           case CAPSLOCK:
            vk = VK_CAPITAL;
            break;
           case SHIFT:
            vk = VK_SHIFT;
            if(GetKeyState(vk) & 0xF000) return;
            uptoo = false;
            break;
           case CTRL:
            vk = VK_CONTROL;
            if(GetKeyState(vk) & 0xF000) return;
            uptoo = false;
            break;
           case BSPACE:
            vk = VK_BACK;
            break;
           case ENTER:
            vk = VkKeyScan(0x0D) & 0xFF;
            break;
           case ALT:
            vk = VK_MENU;
            break;
           case WINDOW:
            vk = VK_LWIN;
            break;
           case HANEN:
            vk = VK_HANGUL;
            break;
           default: break;
         }
      }
      keybd_event(vk, 0, 0, 0);
      if(uptoo)
         keybd_event(vk, 0, KEYEVENTF_KEYUP, 0);
   }
   else{
      char pChar = keydef->cNormal;
      short ks   = VkKeyScan(pChar);
      BYTE key   = ks & 0xFF;
      keybd_event(key, 0, 0, 0);
      keybd_event(key, 0, KEYEVENTF_KEYUP, 0);

      unsigned char vk = VK_SHIFT;
      if(GetKeyState(vk) & 0xF000)
         keybd_event(vk, 0, KEYEVENTF_KEYUP, 0);
      vk = VK_CONTROL;
      if(GetKeyState(vk) & 0xF000)
         keybd_event(vk, 0, KEYEVENTF_KEYUP, 0);
   }
}
//---------------------------------------------------------------------------
void __fastcall TfrmVKey::ReleaseFocus()
{
   ::SetFocus(gFocus);
//   if(IsWindow(gFocus)){
//      HWND wnd = ::GetForegroundWindow();
//      if(IsWindow(wnd)){
//         if(wnd == gFocus)
//            return;
//      }
//      ::SetForegroundWindow(gFocus);
//      ::SetFocus(gFocus);
//   }
}
//---------------------------------------------------------------------------
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
   TPoint pt, ptClient;
   int KeyNo;
   TRect client = gVKey->ClientRect;
   int x = 0;
   int y = -pKeyHeight;
   KEYDEF *key;

   if(nCode >= 0){
      if(wParam == WM_LBUTTONDOWN){
         pt = ((MOUSEHOOKSTRUCT *)lParam)->pt;
         ptClient = gVKey->ScreenToClient(pt);
         for(int i=0; i<kList->Count; i++){
            key = (KEYDEF *)kList->Items[i];
            if((key->cNormal == 0x00) && (key->cShifted == 0x00)){
               x = 0;
               y += pKeyHeight;
            }
            else{
               int width = ((abs(key->cWidth) * pKeyWidth) / 10);
               TRect rc = TRect(x, y, x + width, y + pKeyHeight);
               if(key->cWidth < 0)
                  rc.right = client.right;
               x += width;
               if(PtInRect(rc, ptClient)){
                  gVKey->ReleaseFocus();
                  SendKey(key);
                  key = NULL;
                  return (int)true;
               }
            }
         }
      }
      if(wParam == WM_NCLBUTTONDOWN)
         SetForegroundWindow(gVKey->Handle);
   }
   return CallNextHookEx(HMouseHook, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
void  TfrmVKey::OnWndHookMsg(TMessage Msg)
{
   if(Msg.WParam != (int)Handle)
      hLastAct = (HANDLE)Msg.WParam;
}
//---------------------------------------------------------------------------
void  TfrmVKey::OnWMMouseActivate(TWMMouseActivate Msg)
{
   Msg.Result = MA_NOACTIVATEANDEAT;
   SetForegroundWindow(hLastAct);
}
//---------------------------------------------------------------------------
//void  TfrmVKey::OnWMNCActivate(TWMMouseActivate Msg)
//{
//}
//---------------------------------------------------------------------------


