Exemple #1
0
static int GetWordFromConsolePack(TConsoleParams *params)
{
	int WordLen=0;

	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	if (hStdOut != INVALID_HANDLE_VALUE) {
		CONSOLE_SCREEN_BUFFER_INFO csbi;
		if (GetConsoleScreenBufferInfo(hStdOut, &csbi)) {
			COORD CurPos;
			CurPos.X = csbi.srWindow.Left + (SHORT)(params->Pt.x * (csbi.srWindow.Right - csbi.srWindow.Left + 1) / params->ClientRect.right);
			CurPos.Y = csbi.srWindow.Top + (SHORT)(params->Pt.y * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1) / params->ClientRect.bottom);
			if ((CurPos.X >= 0) && (CurPos.X <= csbi.dwSize.X - 1) && (CurPos.Y >= 0) && (CurPos.Y <= csbi.dwSize.Y - 1)) {
				int BegPos;
				WCHAR *Buf;

				params->BeginPos = CurPos.X;
				CurPos.X = 0;
				Buf = GlobalAlloc(GMEM_FIXED, (csbi.dwSize.X + 1)*sizeof(WCHAR));
				if (Buf) {
					DWORD ActualRead;
					if ((ReadConsoleOutputCharacterW(hStdOut, Buf, csbi.dwSize.X, CurPos, &ActualRead)) && (ActualRead == (DWORD)csbi.dwSize.X)) {
						BegPos=0;
						WordLen=ActualRead;
						if(WordLen>85) {
							while(params->BeginPos-BegPos>43 && WordLen>85) {
								BegPos++; WordLen--;
							}
							if(WordLen>85) WordLen=85;
							params->BeginPos -= BegPos;
						}
						if(WordLen) {
							memset(params->Buffer, 0, sizeof(params->Buffer));
							lstrcpynW(params->Buffer, Buf + BegPos, WordLen+1);
						}
					}
					GlobalFree(Buf);
				}
			}
		}
	}
	return WordLen;
}
Exemple #2
0
// bBashMargin - sh.exe has pad in one space cell on right edge of window
BOOL OnReadConsoleClick(SHORT xPos, SHORT yPos, bool bForce, bool bBashMargin)
{
	TODO("Тут бы нужно еще учитывать, что консоль могла прокрутиться вверх на несколько строк, если был ENABLE_WRAP_AT_EOL_OUTPUT");
	TODO("Еще интересно, что будет, если координата начала вдруг окажется за пределами буфера (типа сузили окно, и курсор уехал)");

	HANDLE hConIn = NULL;
	if (!IsPromptActionAllowed(bForce, bBashMargin, &hConIn))
		return FALSE;

	BOOL lbRc = FALSE, lbWrite = FALSE;
    int nChars = 0;
    DWORD nWritten = 0, dwLastError = 0;

	HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);

	CONSOLE_SCREEN_BUFFER_INFO csbi = {};
	if (GetConsoleScreenBufferInfo(hConOut, &csbi) && csbi.dwSize.X && csbi.dwSize.Y)
	{
		bool bHomeEnd = false;
		lbRc = TRUE;

		// When we are outside of standard ReadConsole[A|W]
		// it's almost impossible to detect where readline was started.
		// So, it's more safe do not try to go upper lines at all.
		if (!gReadConsoleInfo.InReadConsoleTID && (yPos < csbi.dwCursorPosition.Y))
		{
			yPos = csbi.dwCursorPosition.Y;
		}

		nChars = (csbi.dwSize.X * (yPos - csbi.dwCursorPosition.Y))
			+ (xPos - csbi.dwCursorPosition.X);

		if (nChars != 0)
		{
			char* pszLine = (char*)malloc(csbi.dwSize.X+1);
			wchar_t* pwszLine = (wchar_t*)malloc((csbi.dwSize.X+1)*sizeof(*pwszLine));

			if (pszLine && pwszLine)
			{
				int nChecked = 0;
				int iCount;
				DWORD nRead;
				COORD cr;
				SHORT nPrevSpaces = 0, nPrevChars = 0;
				SHORT nWhole = 0, nPrint = 0;
				bool bDBCS = false;
				// Если в консоли выбрана DBCS кодировка - там все не просто
				DWORD nCP = GetConsoleOutputCP();
				if (nCP && nCP != CP_UTF7 && nCP != CP_UTF8 && nCP != 1200 && nCP != 1201)
				{
					CPINFO cp = {};
					if (GetCPInfo(nCP, &cp) && (cp.MaxCharSize > 1))
					{
						bDBCS = true;
					}
				}

				TODO("DBCS!!! Must to convert cursor pos ('DBCS') to char pos!");
				// Ok, теперь нужно проверить, не был ли клик сделан "за пределами строки ввода"

				SHORT y = csbi.dwCursorPosition.Y;
				while (true)
				{
					cr.Y = y;
					if (nChars > 0)
					{
						cr.X = (y == csbi.dwCursorPosition.Y) ? csbi.dwCursorPosition.X : 0;
						iCount = (y == yPos) ? (xPos - cr.X) : (csbi.dwSize.X - cr.X);
						if (iCount < 0)
							break;
					}
					else
					{
						cr.X = 0;
						iCount = ((y == csbi.dwCursorPosition.Y) ? csbi.dwCursorPosition.X : csbi.dwSize.X)
							- ((y == yPos) ? xPos : 0);
						if (iCount < 0)
							break;
					}

					// Считать строку
					if (bDBCS)
					{
						// На DBCS кодировках "ReadConsoleOutputCharacterW" фигню возвращает
						BOOL bReadOk = ReadConsoleOutputCharacterA(hConOut, pszLine, iCount, cr, &nRead);
						dwLastError = GetLastError();

						if (!bReadOk || !nRead)
						{
							// Однако и ReadConsoleOutputCharacterA может глючить, пробуем "W"
							bReadOk = ReadConsoleOutputCharacterW(hConOut, pwszLine, iCount, cr, &nRead);
							dwLastError = GetLastError();

							if (!bReadOk || !nRead)
								break;

							bDBCS = false; // Thread string as simple Unicode.
						}
						else
						{
							nRead = MultiByteToWideChar(nCP, 0, pszLine, nRead, pwszLine, csbi.dwSize.X);
						}

						// Check chars count
						if (((int)nRead) <= 0)
							break;
					}
					else
					{
						if (!ReadConsoleOutputCharacterW(hConOut, pwszLine, iCount, cr, &nRead) || !nRead)
							break;
					}

					if (nRead > (DWORD)csbi.dwSize.X)
					{
						_ASSERTEX(nRead <= (DWORD)csbi.dwSize.X);
						break;
					}
					pwszLine[nRead] = 0;

					nWhole = nPrint = (SHORT)nRead;
					// Сначала посмотреть сколько в конце строки пробелов
					while ((nPrint > 0) && (pwszLine[nPrint-1] == L' '))
					{
						nPrint--;
					}

					// В каком направлении идем
					if (nChars > 0) // Вниз
					{
						// Если знаков (не пробелов) больше 0 - учитываем и концевые пробелы предыдущей строки
						if (nPrint > 0)
						{
							nChecked += nPrevSpaces + nPrint;
						}
						else
						{
							// Если на предыдущей строке значащих символов не было - завершаем
							if (nPrevChars <= 0)
								break;
						}
					}
					else // Вверх
					{
						if (nPrint <= 0)
							break; // На первой же пустой строке мы останавливаемся
						nChecked += nWhole;
					}
					nPrevChars = nPrint;
					nPrevSpaces = nWhole - nPrint;
					_ASSERTEX(nPrevSpaces>=0);


					// Цикл + условие
					if (nChars > 0)
					{
						if ((++y) > yPos)
							break;
					}
					else
					{
						if ((--y) < yPos)
							break;
					}
				}
				SafeFree(pszLine);
				SafeFree(pwszLine);

				// Changed?
				nChars = (nChars > 0) ? nChecked : -nChecked;
				//nChars = (csbi.dwSize.X * (yPos - csbi.dwCursorPosition.Y))
				//	+ (xPos - csbi.dwCursorPosition.X);
			}
		}

		if (nChars != 0)
		{
			int nCount = bHomeEnd ? 1 : (nChars < 0) ? (-nChars) : nChars;
			if (!bHomeEnd && (nCount > (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top))))
			{
				bHomeEnd = true;
				nCount = 1;
			}

			INPUT_RECORD* pr = (INPUT_RECORD*)calloc((size_t)nCount,sizeof(*pr));
			if (pr != NULL)
			{
				WORD vk = bHomeEnd ? ((nChars < 0) ? VK_HOME : VK_END) :
					((nChars < 0) ? VK_LEFT : VK_RIGHT);
				HKL hkl = GetKeyboardLayout(gReadConsoleInfo.InReadConsoleTID ? gReadConsoleInfo.InReadConsoleTID : gReadConsoleInfo.LastReadConsoleInputTID);
				WORD sc = MapVirtualKeyEx(vk, 0/*MAPVK_VK_TO_VSC*/, hkl);
				if (!sc)
				{
					_ASSERTEX(sc!=NULL && "Can't determine SC?");
					sc = (vk == VK_LEFT)  ? 0x4B :
						 (vk == VK_RIGHT) ? 0x4D :
						 (vk == VK_HOME)  ? 0x47 :
						 (vk == VK_RIGHT) ? 0x4F : 0;
				}

				for (int i = 0; i < nCount; i++)
				{
					pr[i].EventType = KEY_EVENT;
					pr[i].Event.KeyEvent.bKeyDown = TRUE;
					pr[i].Event.KeyEvent.wRepeatCount = 1;
					pr[i].Event.KeyEvent.wVirtualKeyCode = vk;
					pr[i].Event.KeyEvent.wVirtualScanCode = sc;
					pr[i].Event.KeyEvent.dwControlKeyState = ENHANCED_KEY;
				}

				while (nCount > 0)
				{
					lbWrite = WriteConsoleInputW(hConIn, pr, min(nCount,256), &nWritten);
					if (!lbWrite || !nWritten)
						break;
					nCount -= nWritten;
				}

				free(pr);
			}
		}
	}

	UNREFERENCED_PARAMETER(dwLastError);
	return lbRc;
}
Exemple #3
0
BOOL OnPromptBsDeleteWord(bool bForce, bool bBashMargin)
{
	HANDLE hConIn = NULL;
	if (!IsPromptActionAllowed(bForce, bBashMargin, &hConIn))
	{
		BsDelWordMsg(L"Skipped due to !IsPromptActionAllowed!");
		return FALSE;
	}

	int iBSCount = 0;
	BOOL lbWrite = FALSE;
	DWORD dwLastError = 0;

	HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);

	CONSOLE_SCREEN_BUFFER_INFO csbi = {};
	if (GetConsoleScreenBufferInfo(hConOut, &csbi) && csbi.dwSize.X && csbi.dwSize.Y)
	{
		if (csbi.dwCursorPosition.X == 0)
		{
			iBSCount = 1;
		}
		else
		{
			bool bDBCS = false;
			DWORD nRead = 0;
			BOOL bReadOk = FALSE;

			// Если в консоли выбрана DBCS кодировка - там все не просто
			DWORD nCP = GetConsoleOutputCP();
			if (nCP && nCP != CP_UTF7 && nCP != CP_UTF8 && nCP != 1200 && nCP != 1201)
			{
				CPINFO cp = {};
				if (GetCPInfo(nCP, &cp) && (cp.MaxCharSize > 1))
				{
					bDBCS = true;
				}
			}

			#ifdef _DEBUG
			wchar_t szDbg[120];
			_wsprintf(szDbg, SKIPCOUNT(szDbg) L"CP=%u bDBCS=%u IsDbcs=%u X=%i", nCP, bDBCS, IsDbcs(), csbi.dwCursorPosition.X);
			BsDelWordMsg(szDbg);
			#endif

			int xPos = csbi.dwCursorPosition.X;
			COORD cr = {0, csbi.dwCursorPosition.Y};
			if ((xPos == 0) && (csbi.dwCursorPosition.Y > 0))
			{
				cr.Y--;
				xPos = csbi.dwSize.X;
			}
			COORD cursorFix = {xPos, cr.Y};

			wchar_t* pwszLine = (wchar_t*)malloc((csbi.dwSize.X+1)*sizeof(*pwszLine));


			if (pwszLine)
			{
				pwszLine[csbi.dwSize.X] = 0;

				// Считать строку
				if (bDBCS)
				{
					CHAR_INFO *pData = (CHAR_INFO*)calloc(csbi.dwSize.X, sizeof(CHAR_INFO));
					COORD bufSize = {csbi.dwSize.X, 1};
					SMALL_RECT rgn = {0, cr.Y, csbi.dwSize.X-1, cr.Y};

					bReadOk = ReadConsoleOutputEx(hConOut, pData, bufSize, rgn, &cursorFix);
					dwLastError = GetLastError();
					_ASSERTE(bReadOk);

					if (bReadOk)
					{
						for (int i = 0; i < csbi.dwSize.X; i++)
							pwszLine[i] = pData[i].Char.UnicodeChar;
						nRead = csbi.dwSize.X;
						xPos = cursorFix.X;
					}

					SafeFree(pData);
				}
				else
				{
					bReadOk = ReadConsoleOutputCharacterW(hConOut, pwszLine, csbi.dwSize.X, cr, &nRead);
					if (bReadOk && !nRead)
						bReadOk = FALSE;
				}

				if (bReadOk)
				{
					// Count chars
					{
						if ((int)nRead >= xPos)
						{
							int i = xPos - 1;
							_ASSERTEX(i >= 0);

							iBSCount = 0;

							// Only RIGHT brackets here to be sure that `(x86)` will be deleted including left bracket
							wchar_t cBreaks[] = L"\x20\xA0>])}$.,/\\\"";

							// Delete all `spaces` first
							while ((i >= 0) && ((pwszLine[i] == ucSpace) || (pwszLine[i] == ucNoBreakSpace)))
								iBSCount++, i--;
							_ASSERTE(cBreaks[0]==ucSpace && cBreaks[1]==ucNoBreakSpace);
							// delimiters
							while ((i >= 0) && wcschr(cBreaks+2, pwszLine[i]))
								iBSCount++, i--;
							// and all `NON-spaces`
							while ((i >= 0) && !wcschr(cBreaks, pwszLine[i]))
								iBSCount++, i--;
						}
					}
				}
			}

			// Done, string was processed
			SafeFree(pwszLine);
		}
	}
	else
	{
		BsDelWordMsg(L"GetConsoleScreenBufferInfo failed");
	}

	if (iBSCount > 0)
	{
		INPUT_RECORD* pr = (INPUT_RECORD*)calloc((size_t)iBSCount,sizeof(*pr));
		if (pr != NULL)
		{
			WORD vk = VK_BACK;
			HKL hkl = GetKeyboardLayout(gReadConsoleInfo.InReadConsoleTID ? gReadConsoleInfo.InReadConsoleTID : gReadConsoleInfo.LastReadConsoleInputTID);
			WORD sc = MapVirtualKeyEx(vk, 0/*MAPVK_VK_TO_VSC*/, hkl);
			if (!sc)
			{
				_ASSERTEX(sc!=NULL && "Can't determine SC?");
				sc = 0x0E;
			}

			for (int i = 0; i < iBSCount; i++)
			{
				pr[i].EventType = KEY_EVENT;
				pr[i].Event.KeyEvent.bKeyDown = TRUE;
				pr[i].Event.KeyEvent.wRepeatCount = 1;
				pr[i].Event.KeyEvent.wVirtualKeyCode = vk;
				pr[i].Event.KeyEvent.wVirtualScanCode = sc;
				pr[i].Event.KeyEvent.uChar.UnicodeChar = vk; // BS
				pr[i].Event.KeyEvent.dwControlKeyState = 0;
			}

			DWORD nWritten = 0;

			while (iBSCount > 0)
			{
				lbWrite = WriteConsoleInputW(hConIn, pr, min(iBSCount,256), &nWritten);
				if (!lbWrite || !nWritten)
					break;
				iBSCount -= nWritten;
			}

			free(pr);
		}
	}
	else
	{
		BsDelWordMsg(L"Nothing to delete");
	}

	UNREFERENCED_PARAMETER(dwLastError);
	return FALSE;
}
Exemple #4
0
// Консоль любит глючить, при попытках запроса более определенного количества ячеек.
// MAX_CONREAD_SIZE подобрано экспериментально
BOOL ReadConsoleOutputEx(HANDLE hOut, CHAR_INFO *pData, COORD bufSize, SMALL_RECT rgn)
{
	BOOL lbRc = FALSE;

	DWORD nTick1 = GetTickCount(), nTick2 = 0, nTick3 = 0, nTick4 = 0, nTick5 = 0;

	static bool bDBCS = false, bDBCS_Checked = false;
	if (!bDBCS_Checked)
	{
		bDBCS = (GetSystemMetrics(SM_DBCSENABLED) != 0);
		bDBCS_Checked = true;
	}

	bool   bDBCS_CP = bDBCS;
	LPCSTR szLeads = NULL;
	UINT   MaxCharSize = 0;
	DWORD  nCP, nCP1, nMode;

	if (bDBCS)
	{
		nCP = GetConsoleOutputCP();
		nCP1 = GetConsoleCP();
		GetConsoleMode(hOut, &nMode);

		szLeads = GetCpInfoLeads(nCP, &MaxCharSize);
		if (!szLeads || !*szLeads || MaxCharSize < 2)
		{
			bDBCS_CP = false;
		}
	}

	size_t nBufWidth = bufSize.X;
	int nWidth = (rgn.Right - rgn.Left + 1);
	int nHeight = (rgn.Bottom - rgn.Top + 1);
	int nCurSize = nWidth * nHeight;

	_ASSERTE(bufSize.X >= nWidth);
	_ASSERTE(bufSize.Y >= nHeight);
	_ASSERTE(rgn.Top>=0 && rgn.Bottom>=rgn.Top);
	_ASSERTE(rgn.Left>=0 && rgn.Right>=rgn.Left);

	//MSectionLock RCS;
	//if (gpSrv->pReqSizeSection && !RCS.Lock(gpSrv->pReqSizeSection, TRUE, 30000))
	//{
	//	_ASSERTE(FALSE);
	//	SetLastError(ERROR_INVALID_PARAMETER);
	//	return FALSE;

	//}

	COORD bufCoord = {0,0};
	DWORD dwErrCode = 0;

	nTick2 = GetTickCount();

	if (!bDBCS_CP && (nCurSize <= MAX_CONREAD_SIZE))
	{
		if (ReadConsoleOutputW(hOut, pData, bufSize, bufCoord, &rgn))
			lbRc = TRUE;
		nTick3 = GetTickCount();
	}

	if (!lbRc)
	{
		// Придется читать построчно
		
		// Теоретически - можно и блоками, но оверхед очень маленький, а велик
		// шанс обломаться, если консоль "глючит". Поэтому построчно...

		//bufSize.X = TextWidth;
		bufSize.Y = 1;
		bufCoord.X = 0; bufCoord.Y = 0;
		//rgn = gpSrv->sbi.srWindow;

		int Y1 = rgn.Top;
		int Y2 = rgn.Bottom;

		CHAR_INFO* pLine = pData;
		if (!bDBCS_CP)
		{
			for (int y = Y1; y <= Y2; y++, rgn.Top++, pLine+=nBufWidth)
			{
				nTick3 = GetTickCount();
				rgn.Bottom = rgn.Top;
				lbRc = ReadConsoleOutputW(hOut, pLine, bufSize, bufCoord, &rgn);
				if (!lbRc)
				{
					dwErrCode = GetLastError();
					_ASSERTE(FALSE && "ReadConsoleOutputW failed in MyReadConsoleOutput");
					break;
				}
				nTick4 = GetTickCount();
			}
		}
		else
		{
			DWORD nAttrsMax = bufSize.X;
			DWORD nCharsMax = nAttrsMax/* *4 */; // -- максимум там вроде на некоторых CP - 4 байта
			wchar_t* pszChars = (wchar_t*)malloc(nCharsMax*sizeof(*pszChars));
			char* pszCharsA = (char*)malloc(nCharsMax*sizeof(*pszCharsA));
			WORD* pnAttrs = (WORD*)malloc(bufSize.X*sizeof(*pnAttrs));
			if (pszChars && pszCharsA && pnAttrs)
			{
				COORD crRead = {rgn.Left,Y1};
				DWORD nChars, nAttrs, nCharsA;
				CHAR_INFO* pLine = pData;
				for (; crRead.Y <= Y2; crRead.Y++, pLine+=nBufWidth)
				{
					nTick3 = GetTickCount();
					rgn.Bottom = rgn.Top;

					nChars = nCharsA = nAttrs = 0;
					BOOL lbRcTxt = ReadConsoleOutputCharacterA(hOut, pszCharsA, nCharsMax, crRead, &nCharsA);
					dwErrCode = GetLastError();
					if (!lbRcTxt || !nCharsA)
					{
						nCharsA = 0;
						lbRcTxt = ReadConsoleOutputCharacterW(hOut, pszChars, nCharsMax, crRead, &nChars);
						dwErrCode = GetLastError();
					}
					BOOL lbRcAtr = ReadConsoleOutputAttribute(hOut, pnAttrs, bufSize.X, crRead, &nAttrs);
					dwErrCode = GetLastError();
					
					lbRc = lbRcTxt && lbRcAtr;

					if (!lbRc)
					{
						dwErrCode = GetLastError();
						_ASSERTE(FALSE && "ReadConsoleOutputAttribute failed in MyReadConsoleOutput");

						CHAR_INFO* p = pLine;
						for (size_t i = 0; i < nAttrsMax; ++i, ++p)
						{
							p->Attributes = 4; // red on black
							p->Char.UnicodeChar = 0xFFFE; // not a character
						}

						break;
					}
					else
					{
						if (nCharsA)
						{
							nChars = MultiByteToWideChar(nCP, 0, pszCharsA, nCharsA, pszChars, nCharsMax);
						}
						CHAR_INFO* p = pLine;
						wchar_t* psz = pszChars;
						WORD* pn = pnAttrs;
						//int i = nAttrsMax;
						//while ((i--) > 0)
						//{
						//	p->Attributes = *(pn++);
						//	p->Char.UnicodeChar = *(psz++);
						//	p++;
						//}
						size_t x1 = min(nChars,nAttrsMax);
						size_t x2 = nAttrsMax;
						for (size_t i = 0; i < x1; ++i, ++p)
						{
							p->Attributes = *pn;
							p->Char.UnicodeChar = *psz;

							WARNING("Некорректно! pn может указывать на начало блока DBCS/QBCS");
							pn++; // += MaxCharSize;
							psz++;
						}
						WORD nLastAttr = pnAttrs[max(0,(int)nAttrs-1)];
						for (size_t i = x1; i < x2; ++i, ++p)
						{
							p->Attributes = nLastAttr;
							p->Char.UnicodeChar = L' ';
						}
					}
					nTick4 = GetTickCount();
				}
			}
			SafeFree(pszChars);
			SafeFree(pszCharsA);
			SafeFree(pnAttrs);
		}

		nTick5 = GetTickCount();
	}

	UNREFERENCED_PARAMETER(nTick1);
	UNREFERENCED_PARAMETER(nTick2);
	UNREFERENCED_PARAMETER(nTick3);
	UNREFERENCED_PARAMETER(nTick4);
	UNREFERENCED_PARAMETER(nTick5);
	return lbRc;
}