//##############################################################################
//#################### код для реализации метода SendKeys ######################
#define WorkBufLen							0x00000028
#define MaxSendKeyRecs						0x00000029
#define MaxInt								0x7FFFFFFF
#define MaxLongint							0x7FFFFFFF

static char WorkBuf[WorkBufLen+1];
int AllocationSize;

typedef BYTE THKeys[MaxLongint];

typedef struct tsendkey {
	char*  Name;
	BYTE VKey;
} TSendKey;


static TSendKey SendKeyRecs [] = {
	{"BKSP", VK_BACK},
	{"BS", VK_BACK},
	{"BACKSPACE", VK_BACK},
	{"BREAK", VK_CANCEL},
	{"CAPSLOCK", VK_CAPITAL},
	{"CLEAR", VK_CLEAR},
	{"DEL", VK_DELETE},
	{"DELETE", VK_DELETE},
	{"DOWN", VK_DOWN},
	{"END", VK_END},
	{"ENTER", VK_RETURN},
	{"ESC", VK_ESCAPE},
	{"ESCAPE", VK_ESCAPE},
	{"F1", VK_F1},
	{"F10", VK_F10},
	{"F11", VK_F11},
	{"F12", VK_F12},
	{"F13", VK_F13},
	{"F14", VK_F14},
	{"F15", VK_F15},
	{"F16", VK_F16},
	{"F2", VK_F2},
	{"F3", VK_F3},
	{"F4", VK_F4},
	{"F5", VK_F5},
	{"F6", VK_F6},
	{"F7", VK_F7},
	{"F8", VK_F8},
	{"F9", VK_F9},
	{"HELP", VK_HELP},
	{"HOME", VK_HOME},
	{"INS", VK_INSERT},
	{"LEFT", VK_LEFT},
	{"NUMLOCK", VK_NUMLOCK},
	{"PGDN", VK_NEXT},
	{"PGUP", VK_PRIOR},
	{"PRTSC", VK_PRINT},
	{"RIGHT", VK_RIGHT},
	{"SCROLLLOCK", VK_SCROLL},
	{"TAB", VK_TAB},
	{"UP", VK_UP}
}; 

#define  VK_NULL 0
#define  VK_SemiColon 186
#define  VK_Equal 187
#define  VK_Comma 188
#define  VK_Minus 189
#define  VK_Period 190
#define  VK_Slash 191
#define  VK_BackQuote 192
#define  VK_LeftBracket 219
#define  VK_BackSlash 220
#define  VK_RightBracket 221
#define  VK_Quote 222
#define  VK_Last VK_Quote

#define INVALIDKEY  0xFFFF
#define VKKEYSCANSHIFTON  0x01
#define VKKEYSCANCTRLON  0x02
#define VKKEYSCANALTON  0x04

bool UsingParens, ShiftDown, ControlDown, AltDown, FoundClose;
char* PosSpace;
int I, L;
WORD  NumTimes, MKey;
char KeyString[20];

bool WWait;

bool BitSet(BYTE BitTable, BYTE BitMask)
{
	return ((BitTable & BitMask) != 0);
}


void SetBit(BYTE* BitTable, BYTE BitMask)
{
	*BitTable |= BitMask;
}

void KeyboardEvent(BYTE VKey, BYTE ScanCode, DWORD Flags)
{ 
	
	//keybd_event(VKey, ScanCode, Flags, 0);
	INPUT input;
	input.type = INPUT_KEYBOARD;
	input.ki.wVk = VKey;
	input.ki.wScan = ScanCode;
	input.ki.dwFlags = Flags;
	input.ki.time = 1;
	input.ki.dwExtraInfo = 0;
	
	SendInput(1, &input, sizeof(INPUT));

	if (WWait)
	{
		MSG KeyboardMsg;
		//while (PeekMessage(&KeyboardMsg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
		while (PeekMessage(&KeyboardMsg, 0, 0, 0, PM_REMOVE))
		{
			if(!ShiftDown && !ControlDown && !AltDown)
				TranslateMessage(&KeyboardMsg);
			DispatchMessage(&KeyboardMsg);
		}
	}

}

void SendKeyDown(BYTE VKey, WORD NumTimes, bool GenUpMsg)
{
	WORD Cnt;
	BYTE ScanCode;
	bool NumState;
	BYTE KeyBoardState[256];
	
	if (VKey == VK_NUMLOCK)
	{
		NumState = GetKeyState(VK_NUMLOCK) & 1;
		GetKeyboardState(KeyBoardState);
		if (NumState) 
		{
			KeyBoardState[VK_NUMLOCK] &=  !1;
		}
		else
		{
			KeyBoardState[VK_NUMLOCK] |= 1;
		}
		SetKeyboardState(KeyBoardState);
		return;
	}
	ScanCode = (BYTE) MapVirtualKey(VKey, 0);
	for(Cnt = 1;Cnt <= NumTimes; Cnt++)
	{
		switch (VKey) 
		{
		case VK_UP:
		case VK_DOWN:
		case VK_LEFT:
		case VK_RIGHT:
		case VK_HOME:
		case VK_END:
		case VK_PRIOR:
		case VK_NEXT:
		case VK_INSERT:
		case VK_DELETE:
			KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);
			if (GenUpMsg) 
				KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP);
			break;
		default:
			KeyboardEvent(VKey, ScanCode, 0);
			if (GenUpMsg)
				KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
			break;
		}
	}
}

void SendKeyUp(BYTE VKey)
{
	BYTE ScanCode;
	
	ScanCode = (BYTE) MapVirtualKey(VKey, 0);
	switch (VKey) 
	{
	case VK_UP:
	case VK_DOWN:
	case VK_LEFT:
	case VK_RIGHT:
	case VK_HOME:
	case VK_END:
	case VK_PRIOR:
	case VK_NEXT:
	case VK_INSERT:
	case VK_DELETE:
		KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY & KEYEVENTF_KEYUP);
		break;
	default:
		KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
		break;
	}  
}
void PopUpShiftKeys()
{
	if (!UsingParens)
	{
		if (ShiftDown) SendKeyUp(VK_SHIFT);
		if (ControlDown) SendKeyUp(VK_CONTROL);
		if (AltDown) SendKeyUp(VK_MENU);
		ShiftDown = false;
		ControlDown = false;
		AltDown = false;
	}
}

void SendKey(WORD MKey, WORD NumTimes, bool GenDownMsg)
{
	//PopUpShiftKeys();
	if (BitSet(MKey >> 8, VKKEYSCANSHIFTON))
		SendKeyDown(VK_SHIFT, 1, false);
	if (BitSet(MKey >> 8, VKKEYSCANCTRLON))
		SendKeyDown(VK_CONTROL, 1, false);
	if (BitSet(MKey >> 8, VKKEYSCANALTON))
		SendKeyDown(VK_MENU, 1, false);
	SendKeyDown((BYTE)MKey, NumTimes, GenDownMsg);
	if (BitSet(MKey >> 8, VKKEYSCANSHIFTON))
		SendKeyUp(VK_SHIFT);
	if (BitSet(MKey >> 8, VKKEYSCANCTRLON))
		SendKeyUp(VK_CONTROL);
	if (BitSet(MKey >> 8, VKKEYSCANALTON))
		SendKeyUp(VK_MENU);
}

//{Implements a simple binary search to locate special key name strings}

WORD StringToVKey(char* KeyString)
{
	bool Found, Collided;
	BYTE Bottom, Top, Middle;
	WORD Res;
	
	Res = INVALIDKEY;
	Bottom = 1;
	Top = MaxSendKeyRecs;
	Found = false;
	Middle = (Bottom + Top) >> 1;
	do
	{
		Collided = ((Bottom == Middle) || (Top == Middle));
		if (strcmp(KeyString, SendKeyRecs[Middle].Name) == 0)
		{
			Found = true;
			Res = SendKeyRecs[Middle].VKey;
		}
		else
		{
			if (strcmp(KeyString, SendKeyRecs[Middle].Name) > 0) Bottom = Middle;
			else Top = Middle;
			Middle = (Bottom + Top + 1) >> 1;
		}
	} while( !((Found) || (Collided)) );
	return Res;
}

bool SendKeys(char* SendKeysString, bool Wait, LPCTSTR lang)
{
	bool Res;
	char cp[2];
	char temp[20];
	HKL curr_dwhkl;
	HKL dwhkl;
	
	curr_dwhkl = GetKeyboardLayout(0);
	dwhkl = LoadKeyboardLayout(lang,KLF_ACTIVATE);
	
	WWait = Wait;
	cp[0] = 0;
	cp[1] = 0;
	AllocationSize = MaxInt;
	Res = false;
	UsingParens = false;
	ShiftDown = false;
	ControlDown = false;
	AltDown = false;
	I = 0;
	L = strlen(SendKeysString);
	if (L > AllocationSize) L = AllocationSize;
	if (L == 0) return Res;
	
	while (I < L)
	{
		switch (SendKeysString[I])
		{
		case '(' :
			UsingParens = true;
			I++;
			break;
		case ')' :
			UsingParens = false;
			PopUpShiftKeys();
			I++;
			break;
		case '%' :
			AltDown = true;
			SendKeyDown(VK_MENU, 1, false);
			I++;
			break;
		case '+' :
			ShiftDown = true;
			SendKeyDown(VK_SHIFT, 1, false);
			I++;
			break;
		case '^' :
			ControlDown = true;
			SendKeyDown(VK_CONTROL, 1, false);
			I++;
			break;
		case '{' : 
			NumTimes = 1;
			if (SendKeysString[I + 1] == '{')
			{
				MKey = VK_LeftBracket;
				SetBit((BYTE*)((int)&MKey+1), VKKEYSCANSHIFTON);
				SendKey(MKey, 1, true);
				PopUpShiftKeys();
				I += 3;
				continue;// goto Cont;
			}
			KeyString[0] = 0;
			FoundClose = false;
			while (I<=L)
			{
				I++;
				if (SendKeysString[I] == '}')
				{
					FoundClose = true;
					I++;
					break;
				}
				cp[0] = toupper(SendKeysString[I]);
				strcat(KeyString, cp);
			} 
			if (!FoundClose) return Res;
			if (SendKeysString[I] == '}')
			{
				MKey = VK_RightBracket;
				SetBit((BYTE*)((int)&MKey+1),VKKEYSCANSHIFTON);
				SendKey(MKey, 1, true);
				PopUpShiftKeys();
				I++;
				continue;// goto Cont;
			}
			PosSpace = strchr(KeyString, ' ');
			if (PosSpace)
			{ 
				*PosSpace = 0;
				PosSpace++;
				strcpy(temp, PosSpace);
				NumTimes = atoi(temp);
			}
			if (strlen(KeyString) == 1)
			{
				MKey = VkKeyScanEx(KeyString[0],dwhkl);
			}
			else
			{
				if (KeyString[0] == '$')
				{
					KeyString[0] = ' ';
					MKey = atoi(KeyString);
				}
				else
				{
					MKey = StringToVKey(KeyString);
				}
			}
			if (MKey != INVALIDKEY)
			{
				SendKey(MKey, NumTimes, true);
				PopUpShiftKeys();
				continue;// goto Cont;
			}
			break;
		case '~' : 
			SendKeyDown(VK_RETURN, 1, true);
			PopUpShiftKeys();
			I++;
			break;
		default:
			MKey = VkKeyScanEx(SendKeysString[I],dwhkl);
			if (MKey != INVALIDKEY)
			{
				SendKey(MKey, 1, true);
				PopUpShiftKeys();
			} 
			else
			{
				Res = false;
				return Res;
			}
			I++;
			break;
    }
	//Cont:
  }
  Res = true;
  PopUpShiftKeys();
  ActivateKeyboardLayout(curr_dwhkl,KLF_REORDER);
  return Res;
}
//******************************************************************************
