#include "text_operations.h"

struct EditStreamData {
	PBYTE pbBuff;
	int cbBuff;
	int iCurrent;
};

static DWORD CALLBACK EditStreamOutRtf(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	struct EditStreamData *esd = (struct EditStreamData*)dwCookie;
	esd->cbBuff += cb;
	esd->pbBuff = (PBYTE)realloc(esd->pbBuff, esd->cbBuff+sizeof(TCHAR));
	CopyMemory(esd->pbBuff+esd->iCurrent, pbBuff, cb);
	esd->iCurrent += cb;
	esd->pbBuff[esd->iCurrent] = 0;
	
		esd->pbBuff[esd->iCurrent+1] = 0;
	
	*pcb = cb;
	return 0;
}

LPTSTR GeTStringFromStreamData(struct EditStreamData *esd)
{
	LPTSTR ptszTemp, ptszOutText;
	DWORD i, k;

	ptszOutText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
	ptszTemp = (TCHAR*)esd->pbBuff;
	
	for (i = k = 0;i<_tcslen(ptszTemp);i++) 
		if ((ptszTemp[i] == 0x0A)||(ptszTemp[i] == 0x2028))
			ptszOutText[k++] = 0x0D;
		else if (ptszTemp[i] == 0x0D) 
			{
				ptszOutText[k++] = 0x0D;
				if (ptszTemp[i+1] == 0x0A) i++;
			} 
		else 
			ptszOutText[k++] = ptszTemp[i];
	
	ptszOutText[k] = 0;
	return ptszOutText;
}


BOOL CopyTextToClipboard(LPTSTR ptszText)
{
	HGLOBAL hCopy;
	
	if (OpenClipboard(NULL)) 
	{
		EmptyClipboard(); 
		hCopy = GlobalAlloc(GMEM_MOVEABLE, (_tcslen(ptszText)+1)*sizeof(TCHAR));
		_tcscpy((TCHAR*)GlobalLock(hCopy), ptszText);
		GlobalUnlock(hCopy);

	
			SetClipboardData(CF_UNICODETEXT, hCopy);
		
		
		CloseClipboard(); 
		return TRUE;
	}
	else
		return FALSE;
}

LPSTR GetNameOfLayout(HKL hklLayout)
{
	LPSTR ptszLayName = (LPSTR)mir_alloc(KL_NAMELENGTH+1);
	sprintf(ptszLayName, "%08x", hklLayout);
	return ptszLayName;
}

LPTSTR GetShortNameOfLayout(HKL hklLayout)
{
	DWORD dwLcid;
	TCHAR szLI[20];
	LPTSTR ptszLiShort;
	
	ptszLiShort = (LPTSTR)mir_alloc(3*sizeof(TCHAR));
	dwLcid = MAKELCID(hklLayout, 0);
	GetLocaleInfo(dwLcid, LOCALE_SISO639LANGNAME , szLI, 10);
	ptszLiShort[0] = toupper(szLI[0]);
	ptszLiShort[1] = toupper(szLI[1]);
	ptszLiShort[2] = 0;

	return ptszLiShort;
}

HKL GetNextLayout(HKL hklCurLay)
{
	DWORD i;
	for(i = 0; i < bLayNum; i++) 
	if (hklLayouts[i] == hklCurLay)
		return hklLayouts[(i+1)%(bLayNum)];
	
	return NULL;
}

LPTSTR GenerateLayoutString(HKL hklLayout)
{
	LPTSTR ptszLayStr, ptszTemp;
	SHORT shVirtualKey;
	UINT iScanCode;
	BYTE bState[256] = {0};
	DWORD i, j;
	int	iRes;

	ptszLayStr = (LPTSTR)mir_alloc(100*sizeof(TCHAR));
	ptszTemp = (LPTSTR)mir_alloc(3*sizeof(TCHAR));
	ptszTemp[0] = 0;
	for(i = 0;i<_tcslen(ptszKeybEng);i++)
	{		
		shVirtualKey = VkKeyScanEx(ptszKeybEng[i], hklEng);		
		iScanCode = MapVirtualKeyEx(shVirtualKey&0x00FF, 0, hklEng);
		
		for (j = 0;j<256;j++)
			bState[j] = 0;		
 
 		if (shVirtualKey&0x0100) bState[VK_SHIFT] = 0x80;
 		if (shVirtualKey&0x0200) bState[VK_CONTROL] = 0x80;
 		if (shVirtualKey&0x0400) bState[VK_MENU] = 0x80;

		shVirtualKey = MapVirtualKeyEx(iScanCode, 1, hklLayout);
		bState[shVirtualKey&0x00FF] = 0x80;

		
			iRes = ToUnicodeEx(shVirtualKey, iScanCode, bState, ptszTemp, 3, 0, hklLayout);
			// ������ �� ���-����
			if (iRes<0) ToUnicodeEx(shVirtualKey, iScanCode, bState, ptszTemp, 3, 0, hklLayout);
		
			
			//���� ��� ������� ������� ������, ��� �� ������� ������, �� �������� "��������"
			if (ptszTemp[0] == 0) ptszLayStr[i] = 3; else ptszLayStr[i] = ptszTemp[0];
	}
	ptszLayStr[i] = 0;
	
	mir_free(ptszTemp);
	return ptszLayStr;
}

LPTSTR GetLayoutString(HKL hklLayout)
{
	DWORD i;
	for (i = 0;i<bLayNum;i++)
		if (hklLayouts[i] == hklLayout)
			return ptszLayStrings[i];
	return NULL;
}

LPTSTR ChangeTextCase(LPCTSTR ptszInText)
{
	LPTSTR ptszOutText;
	DWORD i;

	ptszOutText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));

	_tcscpy(ptszOutText, ptszInText);

	for (i = 0;i<_tcslen(ptszInText);i++)
	{		
		CharUpperBuff(&ptszOutText[i], 1);

		if (ptszOutText[i] == ptszInText[i])
			CharLowerBuff(&ptszOutText[i], 1);
	}
	return ptszOutText;

}

LPTSTR ChangeTextLayout(LPCTSTR ptszInText, HKL hklCurLay, HKL hklToLay, BOOL TwoWay)
{
	LPTSTR ptszOutText;
	DWORD i, j;
	BOOL Found;

	LPTSTR ptszKeybCur, ptszKeybNext;

	ptszOutText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
	
	_tcscpy(ptszOutText, ptszInText);

	if ((hklCurLay == NULL)||(hklToLay == NULL))
		return ptszOutText;

	ptszKeybCur = GetLayoutString(hklCurLay);
	ptszKeybNext = GetLayoutString(hklToLay);
	
	if ((ptszKeybCur == 0)||(ptszKeybNext == 0))
		return ptszOutText;

	for (i = 0;i<_tcslen(ptszInText);i++)
	{
		Found = FALSE;
		for (j = 0;(j<_tcslen(ptszKeybCur) && (!Found));j++)
			if (ptszKeybCur[j] == ptszInText[i]) 
			{
				Found = TRUE;
				if (_tcslen(ptszKeybNext)>=j)
					ptszOutText[i] = ptszKeybNext[j];
			}
		
		if (TwoWay && (!Found))
			for (j = 0;(j<_tcslen(ptszKeybNext) && (!Found));j++)
				if (ptszKeybNext[j] == ptszInText[i]) 
				{
					Found = TRUE;
					if (_tcslen(ptszKeybCur)>=j)
						ptszOutText[i] = ptszKeybCur[j];
				}
	};	
	return ptszOutText;
}

HKL GetLayoutOfText(LPCTSTR ptszInText)
{
	DWORD i, j;
	LPTSTR ptszKeybBuff;
	DWORD dwCountSymbols, dwMaxSymbols, dwTemp;
	HKL hklCurLay;

	hklCurLay = hklLayouts[0];
	ptszKeybBuff = ptszLayStrings[0];
	dwMaxSymbols = dwTemp = 0;

	for (j = 0;j<_tcslen(ptszInText);j++)
		if (_tcschr(ptszKeybBuff, ptszInText[j]) != NULL) ++dwMaxSymbols;

	for(i = 1; i < bLayNum; i++) 
	{
		ptszKeybBuff = ptszLayStrings[i];
		dwCountSymbols = 0;
			
		for (j = 0;j<_tcslen(ptszInText);j++)
			if (_tcschr(ptszKeybBuff, ptszInText[j]) != NULL) ++dwCountSymbols;
		
		if (dwCountSymbols == dwMaxSymbols)
			dwTemp = dwCountSymbols;
		else if (dwCountSymbols>dwMaxSymbols)
		{
			dwMaxSymbols = dwCountSymbols;
			hklCurLay = hklLayouts[i];
		}
	}

	if (dwMaxSymbols == dwTemp)
		hklCurLay = GetKeyboardLayout(0);
	
	return hklCurLay;
}

int ChangeLayout(HWND hTextWnd, BYTE TextOperation, BOOL CurrentWord)
{
	HKL hklCurLay, hklToLay;

	LPTSTR ptszInText, ptszOutText, ptszMBox, ptszPopupText, ptszTemp;
	IEVIEWEVENT ieEvent;
	CHARRANGE crSelection, crTemp;
	DWORD dwStartWord, dwEndWord;
	int i, iRes;

	BYTE WindowType = WTYPE_Unknown;
	BOOL WindowIsReadOnly, TwoWay;

	EDITSTREAM esStream = {0};
	struct EditStreamData esdData;
	
	POPUPDATAT_V2 pdtData;

	esStream.dwCookie = (DWORD)&esdData;
	esStream.pfnCallback = EditStreamOutRtf;

	if (hTextWnd == NULL)
		hTextWnd = GetFocus();
	if (hTextWnd != NULL)
	{	
		// --------------���������� ��� ����-----------------
		
		ZeroMemory((void *)&ieEvent, sizeof(ieEvent));
		ieEvent.cbSize = sizeof(IEVIEWEVENT);
		ieEvent.dwFlags = 0;
		ieEvent.iType = IEE_GET_SELECTION;
		//event.codepage = 1200;			
		

		if (ServiceExists(MS_HPP_EG_EVENT))
		{
			//�� �� ����� ��� History++
			ieEvent.hwnd = hTextWnd;
			ptszInText = (TCHAR*)CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&ieEvent);				

			if (!IsBadStringPtr(ptszInText, MaxTextSize)) WindowType = WTYPE_HistoryPP;
		}

		if ((WindowType == WTYPE_Unknown) && (ServiceExists(MS_IEVIEW_EVENT)))
		{
			// ����������� ����������� ������ IEView
			ieEvent.hwnd = GetParent(GetParent(hTextWnd));			

			ptszInText = (TCHAR*)CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&ieEvent);			
			if (!IsBadStringPtr(ptszInText, MaxTextSize)) WindowType = WTYPE_IEView;
		}
		
		if (WindowType == WTYPE_Unknown)
		{
			ptszTemp = (LPTSTR)mir_alloc(255*sizeof(TCHAR));
			i = GetClassName(hTextWnd, ptszTemp, 255);
			ptszTemp[i] = 0;

			if (_tcsstr(CharUpper(ptszTemp), _T("RICHEDIT"))  !=  NULL )
			{
				WindowType = WTYPE_RichEdit;
				SendMessage(hTextWnd, EM_EXGETSEL, 0, (LPARAM)&crSelection);
			}
			mir_free(ptszTemp);
		}
		
		if (WindowType == WTYPE_Unknown)
		{
			SendMessage(hTextWnd, EM_GETSEL, (WPARAM)&crSelection.cpMin, (LPARAM)&crSelection.cpMax);
			if ((SendMessage(hTextWnd, WM_GETDLGCODE, (WPARAM)NULL, (LPARAM)NULL)&(DLGC_HASSETSEL)) && (crSelection.cpMin>=0))
				WindowType = WTYPE_Edit;
		}


		//������� ����� �� ���� ��� �������� �����
		if ((WindowType == WTYPE_RichEdit)||(WindowType == WTYPE_Edit)) 
		{
			dwStartWord = dwEndWord = -1;
			SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);	

			//����� ���������
			crTemp = crSelection;
			
			// ���� ������� ���������� �����, �� ������� ���
			if(crSelection.cpMin != crSelection.cpMax)
			{
				if (WindowType == WTYPE_RichEdit)
				{
					ZeroMemory(&esdData, sizeof(esdData));
					
						if (SendMessage(hTextWnd, EM_STREAMOUT, SF_TEXT|SF_UNICODE|SFF_SELECTION, (LPARAM)&esStream)>0)
										
							ptszInText = GeTStringFromStreamData(&esdData);
						else
						{
							SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
							SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
							InvalidateRect(hTextWnd, NULL, FALSE);
							return 1;
						}
				}
				if (WindowType == WTYPE_Edit)
				{
					ptszTemp = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
					ptszInText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
					iRes = SendMessage(hTextWnd, WM_GETTEXT, (WPARAM)MaxTextSize, (LPARAM)ptszTemp); 
					if (!IsBadStringPtr(ptszInText, MaxTextSize) && (iRes>0))
					{
						_tcsncpy(ptszInText, &ptszTemp[crSelection.cpMin], crSelection.cpMax-crSelection.cpMin);
						ptszInText[crSelection.cpMax-crSelection.cpMin] = 0;
						mir_free(ptszTemp);
					}
					else
					{
						SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
						SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
						InvalidateRect(hTextWnd, NULL, FALSE);
						return 1;
					}
				}
			}			
			// ���� ��������� ���, �� ������� ������ �����
			else
			{				
				// �������� ���� ����� � ����
				if (WindowType == WTYPE_RichEdit)
				{
					ZeroMemory(&esdData, sizeof(esdData));
					crTemp.cpMin = 0;
					crTemp.cpMax = -1;
					SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crTemp);
					
						if (SendMessage(hTextWnd, EM_STREAMOUT, SF_TEXT|SF_UNICODE|SFF_SELECTION, (LPARAM)&esStream) != 0)
					
						ptszInText = GeTStringFromStreamData(&esdData);
						else
						{
							SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
							SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
							InvalidateRect(hTextWnd, NULL, FALSE);
							return 1;
						}
				}	
				if (WindowType == WTYPE_Edit)
				{
					ptszInText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
					iRes = SendMessage(hTextWnd, WM_GETTEXT, (WPARAM)MaxTextSize, (LPARAM)ptszInText);
					
					if (!IsBadStringPtr(ptszInText, MaxTextSize) && (iRes>0))
					{
						crTemp.cpMin = 0;
						crTemp.cpMax = (int)_tcslen(ptszInText);
					}
					else
					{
						SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
						SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
						InvalidateRect(hTextWnd, NULL, FALSE);
						return 1;
					}
				}
				// �������� ������� �����
				if (CurrentWord)
				{										
					for (dwStartWord = crSelection.cpMin;(dwStartWord>0) && (_tcschr(ptszSeparators, ptszInText[dwStartWord-1]) == NULL);dwStartWord--);	
					for (dwEndWord = crSelection.cpMin;(dwEndWord<(_tcslen(ptszInText))) && (_tcschr(ptszSeparators, ptszInText[dwEndWord]) == NULL);dwEndWord++);

					crTemp.cpMin = dwStartWord;
					crTemp.cpMax = dwEndWord;
					
					if (WindowType == WTYPE_RichEdit)
					{
						SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crTemp);					
						ZeroMemory(&esdData, sizeof(esdData));
					
							if (SendMessage(hTextWnd, EM_STREAMOUT, SF_TEXT|SF_UNICODE|SFF_SELECTION, (LPARAM)&esStream) != 0)
						
							ptszInText = GeTStringFromStreamData(&esdData);
						else
						{
							SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
							SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
							InvalidateRect(hTextWnd, NULL, FALSE);
							return 1;
						}

					}

					if (WindowType == WTYPE_Edit)
					{
						ptszTemp = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
						_tcsncpy(ptszTemp, &ptszInText[crTemp.cpMin], crTemp.cpMax-crTemp.cpMin);
						ptszTemp[crTemp.cpMax-crTemp.cpMin] = 0;
						_tcscpy(ptszInText, ptszTemp);
						mir_free(ptszTemp);
 						if (_tcslen(ptszInText) == 0)
 						{
 							mir_free(ptszInText);
 							SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
							SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
 							InvalidateRect(hTextWnd, NULL, FALSE);
 							return 1;
 						}
					}
				}
			}
		}
// ---------------������ ����������--------------------
		WindowIsReadOnly = FALSE;
		if ((WindowType == WTYPE_IEView)||(WindowType == WTYPE_HistoryPP)) WindowIsReadOnly = TRUE;
		
		//if ((SendMessage(hTextWnd, EM_GETOPTIONS, 0, 0)&ECO_READONLY))
		if ((WindowType == WTYPE_RichEdit)||(WindowType == WTYPE_Edit)) 
			if (GetWindowLongPtr(hTextWnd, GWL_STYLE)&ES_READONLY)
				WindowIsReadOnly = TRUE;

		// ��� ����� � ��������� � ������ �������� �����  � ���� ������ ��� ������.
		if ((WindowType != WTYPE_Unknown) && (!IsBadStringPtr(ptszInText, MaxTextSize)))	
		if (WindowIsReadOnly)
		{
			ptszMBox = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
			ptszMBox[0] = 0;
 			
			if (TextOperation == TOT_Layout)
			{
				hklCurLay = GetLayoutOfText(ptszInText);
				hklToLay = GetNextLayout(hklCurLay);
				TwoWay = (moOptions.TwoWay) && (bLayNum == 2);

				if (bLayNum == 2)
				{										
					ptszMBox = ChangeTextLayout(ptszInText, hklCurLay, hklToLay, TwoWay);					
				}
				else
				{
					for (i = 0;i<bLayNum;i++)
 						if (hklLayouts[i] != hklCurLay)
 						{
							if (_tcslen(ptszMBox) != 0)
								_tcscat(ptszMBox, _T("\n\n"));
							ptszTemp = GetShortNameOfLayout(hklLayouts[i]);
 							_tcscat(ptszMBox, ptszTemp);
 							_tcscat(ptszMBox, _T(":\n"));
							ptszOutText = ChangeTextLayout(ptszInText, hklCurLay, hklLayouts[i], FALSE);
 							_tcscat(ptszMBox, ptszOutText);
							mir_free(ptszTemp);
							mir_free(ptszOutText);
 					}
				}
			}
			else if (TextOperation == TOT_Case)
			{
				ptszMBox = ChangeTextCase(ptszInText);
			}

			mir_free(ptszInText);

			if ((WindowType == WTYPE_Edit)||(WindowType == WTYPE_RichEdit))
			{
				SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
				SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
				InvalidateRect(hTextWnd, NULL, FALSE);
			}

			if (TextOperation == TOT_Layout)
				SkinPlaySound(SND_ChangeLayout);
			else if (TextOperation == TOT_Case)
				SkinPlaySound(SND_ChangeCase);
			
			if (moOptions.CopyToClipboard)
 				CopyTextToClipboard(ptszMBox);
//-------------------------------������� ������------------------------------------------ 			
 			if (moOptions.ShowPopup)
			{				
				ptszPopupText = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
				_tcscpy(ptszPopupText, ptszMBox);

				pdtData.cbSize = sizeof(POPUPDATAT_V2);
				ZeroMemory(&pdtData, sizeof(pdtData));
				_tcsncpy(pdtData.lptzContactName, TranslateT(ModuleName), MAX_CONTACTNAME);
				_tcsncpy(pdtData.lptzText, ptszPopupText, MAX_SECONDLINE);
				switch(poOptions.bColourType)
				{
				case PPC_POPUP:
					pdtData.colorBack = pdtData.colorText = 0;
					break;
				case PPC_WINDOWS:
					pdtData.colorBack = GetSysColor(COLOR_BTNFACE);
					pdtData.colorText = GetSysColor(COLOR_WINDOWTEXT);
					break;
				case PPC_CUSTOM:
					pdtData.colorBack = poOptions.crBackColour;
					pdtData.colorText = poOptions.crTextColour;
					break;
				default:
					break;
				}
				switch(poOptions.bTimeoutType)
				{
				case PPT_POPUP:
					pdtData.iSeconds = 0;
					break;
				case PPT_PERMANENT:
					pdtData.iSeconds = -1;
					break;
				case PPC_CUSTOM:
					pdtData.iSeconds = poOptions.bTimeout;
					break;
				}			
				pdtData.PluginData  = ptszPopupText;
				
				pdtData.lchIcon = hPopupIcon;
				poOptions.paActions[0].lchIcon = hCopyIcon;
				pdtData.lpActions = poOptions.paActions;
				pdtData.actionCount = 1;

				pdtData.PluginWindowProc = (WNDPROC)CKLPopupDlgProc;
								
				if (CallService(MS_POPUP_ADDPOPUPT, (WPARAM) &pdtData, APF_NEWDATA)<0) 
				{
					mir_free(ptszPopupText);
					MessageBox(NULL, ptszMBox, _T(ModuleName), MB_ICONINFORMATION);
				}
			}
			mir_free(ptszMBox);

		}
//------------------������������� ���� ----------------------------
		else 
		{
				if (TextOperation == TOT_Layout)
				{
					hklCurLay = GetLayoutOfText(ptszInText);
					hklToLay = GetNextLayout(hklCurLay);
					TwoWay = (moOptions.TwoWay) && (bLayNum == 2);
					ptszOutText = ChangeTextLayout(ptszInText, hklCurLay, hklToLay, TwoWay);
				}
				else if (TextOperation == TOT_Case)
				{
					ptszOutText = ChangeTextCase(ptszInText);
				}
				
				if (WindowType == WTYPE_RichEdit)
				{
					SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crTemp);
					SendMessage(hTextWnd, EM_REPLACESEL, FALSE, (LPARAM)ptszOutText);
					SendMessage(hTextWnd, EM_EXSETSEL, 0, (LPARAM)&crSelection);
				}
				else
				{
					ptszTemp = (LPTSTR)mir_alloc(MaxTextSize*sizeof(TCHAR));
					SendMessage(hTextWnd, WM_GETTEXT, (WPARAM)MaxTextSize, (LPARAM)ptszTemp);
					for (i = crTemp.cpMin;i<crTemp.cpMax;i++)
						ptszTemp[i] = ptszOutText[i-crTemp.cpMin];
					SendMessage(hTextWnd, WM_SETTEXT, (WPARAM)NULL, (LPARAM)ptszTemp);
					SendMessage(hTextWnd, EM_SETSEL, crSelection.cpMin, crSelection.cpMax);
					mir_free(ptszTemp);
				}

				// ���������� ��������� ��� ������� ��������� Caps Lock
				if ((TextOperation == TOT_Layout) && (hklToLay != NULL) && (moOptions.ChangeSystemLayout))
					ActivateKeyboardLayout(hklToLay, KLF_SETFORPROCESS);
				else if (TextOperation == TOT_Case)
				{
					 // ���� ����� ����������
					 if (moOptions.bCaseOperations == 0)
					 {
						keybd_event( VK_CAPITAL, 0x45, 0, 0);
						keybd_event( VK_CAPITAL, 0x45, KEYEVENTF_KEYUP, 0);
					 }
					 // ���� ����� ���������
					 else if (moOptions.bCaseOperations == 1)
					 {
						if (GetKeyState(VK_CAPITAL)&0x0001)
						{
							keybd_event( VK_CAPITAL, 0x45, 0, 0);
							keybd_event( VK_CAPITAL, 0x45, KEYEVENTF_KEYUP, 0);
						}
					 }
				}
				
				SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
				InvalidateRect(hTextWnd, NULL, FALSE);
				
				if (TextOperation == TOT_Layout)
					SkinPlaySound(SND_ChangeLayout);
				else if (TextOperation == TOT_Case)
					SkinPlaySound(SND_ChangeCase);

				mir_free(ptszInText);
				mir_free(ptszOutText);
		}
	}
	return 0;
}