Пример #1
0
BOOL SendConsoleEvent(INPUT_RECORD* pr, UINT nCount)
{
	if (!nCount || !pr)
	{
		_ASSERTE(nCount>0 && pr!=NULL);
		return FALSE;
	}

	BOOL fSuccess = FALSE;
	//// Если сейчас идет ресайз - нежелательно помещение в буфер событий
	//if (gpSrv->bInSyncResize)
	//	WaitForSingleObject(gpSrv->hAllowInputEvent, MAX_SYNCSETSIZE_WAIT);
	//DWORD nCurInputCount = 0, cbWritten = 0;
	//INPUT_RECORD irDummy[2] = {{0},{0}};
	//HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn
	// 02.04.2010 Maks - перенесено в WaitConsoleReady
	//// 27.06.2009 Maks - If input queue is not empty - wait for a while, to avoid conflicts with FAR reading queue
	//// 19.02.2010 Maks - замена на GetNumberOfConsoleInputEvents
	////if (PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)) && nCurInputCount > 0) {
	//if (GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)) && nCurInputCount > 0) {
	//	DWORD dwStartTick = GetTickCount();
	//	WARNING("Do NOT wait, but place event in Cyclic queue");
	//	do {
	//		Sleep(5);
	//		//if (!PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)))
	//		if (!GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)))
	//			nCurInputCount = 0;
	//	} while ((nCurInputCount > 0) && ((GetTickCount() - dwStartTick) < MAX_INPUT_QUEUE_EMPTY_WAIT));
	//}
	INPUT_RECORD* prNew = NULL;
	int nAllCount = 0;
	BOOL lbReqEmpty = FALSE;

	for (UINT n = 0; n < nCount; n++)
	{
		if (pr[n].EventType != KEY_EVENT)
		{
			nAllCount++;
			if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT))
			{
				// По всей видимости дурит консоль Windows.
				// Если в буфере сейчас еще есть мышиные события, то запись
				// в буфер возвращает ОК, но считывающее приложение получает 0-событий.
				// В итоге, получаем пропуск некоторых событий, что очень неприятно 
				// при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой)
				if (pr[n].Event.MouseEvent.dwButtonState /*== RIGHTMOST_BUTTON_PRESSED*/)
					lbReqEmpty = TRUE;
			}
		}
		else
		{
			if (!pr[n].Event.KeyEvent.wRepeatCount)
			{
				_ASSERTE(pr[n].Event.KeyEvent.wRepeatCount!=0);
				pr[n].Event.KeyEvent.wRepeatCount = 1;
			}

			nAllCount += pr[n].Event.KeyEvent.wRepeatCount;
		}
	}

	if (nAllCount > (int)nCount)
	{
		prNew = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*nAllCount);

		if (prNew)
		{
			INPUT_RECORD* ppr = prNew;
			INPUT_RECORD* pprMod = NULL;

			for(UINT n = 0; n < nCount; n++)
			{
				*(ppr++) = pr[n];

				if (pr[n].EventType == KEY_EVENT)
				{
					UINT nCurCount = pr[n].Event.KeyEvent.wRepeatCount;

					if (nCurCount > 1)
					{
						pprMod = (ppr-1);
						pprMod->Event.KeyEvent.wRepeatCount = 1;

						for(UINT i = 1; i < nCurCount; i++)
						{
							*(ppr++) = *pprMod;
						}
					}
				}
				else if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT))
				{
					// По всей видимости дурит консоль Windows.
					// Если в буфере сейчас еще есть мышиные события, то запись
					// в буфер возвращает ОК, но считывающее приложение получает 0-событий.
					// В итоге, получаем пропуск некоторых событий, что очень неприятно 
					// при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой)
					if (pr[n].Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
						lbReqEmpty = TRUE;
				}
			}

			pr = prNew;
			_ASSERTE(nAllCount == (ppr-prNew));
			nCount = (UINT)(ppr-prNew);
		}
	}

	// Если не готов - все равно запишем
	DEBUGTEST(BOOL bConReady = )
	WaitConsoleReady(lbReqEmpty);


	DWORD cbWritten = 0;

#ifdef _DEBUG
	wchar_t* pszDbgCurChars = NULL;
	wchar_t szDbg[255];
	for (UINT i = 0; i < nCount; i++)
	{
		if (pr[i].EventType == MOUSE_EVENT)
		{
			_wsprintf(szDbg, SKIPLEN(countof(szDbg))
				L"*** ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n",
				pr[i].Event.MouseEvent.dwMousePosition.X, pr[i].Event.MouseEvent.dwMousePosition.Y, pr[i].Event.MouseEvent.dwButtonState, (pr[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED));
			DEBUGSTRINPUTWRITE(szDbg);
			
			#ifdef _DEBUG
			{
				static int LastMsButton;
				if ((LastMsButton & 1) && (pr[i].Event.MouseEvent.dwButtonState == 0))
				{
					// LButton was Down, now - Up
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
				else if (!LastMsButton && (pr[i].Event.MouseEvent.dwButtonState & 1))
				{
					// LButton was Up, now - Down
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
				else
				{ //-V523
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
			}
			#endif
		}

		// Only for input_bug search purposes in Debug builds
		LONG idx = (InterlockedIncrement(&gn_LogWrittenChars) & (gn_LogWrittenCharsMax-1))*2;
		if (!pszDbgCurChars) pszDbgCurChars = gs_LogWrittenChars+idx;
		if (pr[i].EventType == KEY_EVENT)
		{
			gs_LogWrittenChars[idx++] = pr[i].Event.KeyEvent.bKeyDown ? L'\\' : L'/';
			gs_LogWrittenChars[idx] = pr[i].Event.KeyEvent.uChar.UnicodeChar ? pr[i].Event.KeyEvent.uChar.UnicodeChar : L'.';
		}
		else
		{
			gs_LogWrittenChars[idx++] = L'=';
			switch (pr[i].EventType)
			{
			case MOUSE_EVENT:
				gs_LogWrittenChars[idx] = L'm'; break;
			case WINDOW_BUFFER_SIZE_EVENT:
				gs_LogWrittenChars[idx] = L'w'; break;
			case MENU_EVENT:
				gs_LogWrittenChars[idx] = L'e'; break;
			case FOCUS_EVENT:
				gs_LogWrittenChars[idx] = L'f'; break;
			default:
				gs_LogWrittenChars[idx] = L'x'; break;
			}
		}
		gs_LogWrittenChars[++idx] = 0;
	}
	int nDbgSendLen = pszDbgCurChars ? lstrlen(pszDbgCurChars) : -1;
	SetLastError(0);
#endif


	HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn
	fSuccess = WriteConsoleInput(hIn, pr, nCount, &cbWritten);

	// Error ERROR_INVALID_HANDLE may occurs when ConEmu was Attached to some external console with redirected input.

#ifdef _DEBUG
	DWORD dwErr = GetLastError();
	if (!fSuccess || (nCount != cbWritten))
	{
		_wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"### WriteConsoleInput(Write=%i, Written=%i, Left=%i, Err=x%X)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents(), dwErr);
		DEBUGSTRINPUTWRITEFAIL(szDbg);
	}
	else
	{
		_wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** WriteConsoleInput(Write=%i, Written=%i, Left=%i)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents());
		DEBUGSTRINPUTWRITEALL(szDbg);
	}
	_ASSERTE((fSuccess && cbWritten==nCount) || (!fSuccess && dwErr==ERROR_INVALID_HANDLE && gbAttachMode));
#endif

	if (prNew) free(prNew);

	return fSuccess;
}
Пример #2
0
BOOL SendConsoleEvent(INPUT_RECORD* pr, UINT nCount)
{
	if (!nCount || !pr)
	{
		_ASSERTE(nCount>0 && pr!=NULL);
		return FALSE;
	}

	BOOL fSuccess = FALSE;
	//// Если сейчас идет ресайз - нежелательно помещение в буфер событий
	//if (gpSrv->bInSyncResize)
	//	WaitForSingleObject(gpSrv->hAllowInputEvent, MAX_SYNCSETSIZE_WAIT);
	//DWORD nCurInputCount = 0, cbWritten = 0;
	//INPUT_RECORD irDummy[2] = {{0},{0}};
	//HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn
	// 02.04.2010 Maks - перенесено в WaitConsoleReady
	//// 27.06.2009 Maks - If input queue is not empty - wait for a while, to avoid conflicts with FAR reading queue
	//// 19.02.2010 Maks - замена на GetNumberOfConsoleInputEvents
	////if (PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)) && nCurInputCount > 0) {
	//if (GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)) && nCurInputCount > 0) {
	//	DWORD dwStartTick = GetTickCount();
	//	WARNING("Do NOT wait, but place event in Cyclic queue");
	//	do {
	//		Sleep(5);
	//		//if (!PeekConsoleInput(hIn, irDummy, 1, &(nCurInputCount = 0)))
	//		if (!GetNumberOfConsoleInputEvents(hIn, &(nCurInputCount = 0)))
	//			nCurInputCount = 0;
	//	} while ((nCurInputCount > 0) && ((GetTickCount() - dwStartTick) < MAX_INPUT_QUEUE_EMPTY_WAIT));
	//}
	INPUT_RECORD* prNew = NULL;
	int nAllCount = 0;
	BOOL lbReqEmpty = FALSE;

	for(UINT n = 0; n < nCount; n++)
	{
		if (pr[n].EventType != KEY_EVENT)
		{
			nAllCount++;
			if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT))
			{
				// По всей видимости дурит консоль Windows.
				// Если в буфере сейчас еще есть мышиные события, то запись
				// в буфер возвращает ОК, но считывающее приложение получает 0-событий.
				// В итоге, получаем пропуск некоторых событий, что очень неприятно 
				// при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой)
				if (pr[n].Event.MouseEvent.dwButtonState /*== RIGHTMOST_BUTTON_PRESSED*/)
					lbReqEmpty = TRUE;
			}
		}
		else
		{
			if (!pr[n].Event.KeyEvent.wRepeatCount)
			{
				_ASSERTE(pr[n].Event.KeyEvent.wRepeatCount!=0);
				pr[n].Event.KeyEvent.wRepeatCount = 1;
			}

			nAllCount += pr[n].Event.KeyEvent.wRepeatCount;
		}
	}

	if (nAllCount > (int)nCount)
	{
		prNew = (INPUT_RECORD*)malloc(sizeof(INPUT_RECORD)*nAllCount);

		if (prNew)
		{
			INPUT_RECORD* ppr = prNew;
			INPUT_RECORD* pprMod = NULL;

			for(UINT n = 0; n < nCount; n++)
			{
				*(ppr++) = pr[n];

				if (pr[n].EventType == KEY_EVENT)
				{
					UINT nCurCount = pr[n].Event.KeyEvent.wRepeatCount;

					if (nCurCount > 1)
					{
						pprMod = (ppr-1);
						pprMod->Event.KeyEvent.wRepeatCount = 1;

						for(UINT i = 1; i < nCurCount; i++)
						{
							*(ppr++) = *pprMod;
						}
					}
				}
				else if (!lbReqEmpty && (pr[n].EventType == MOUSE_EVENT))
				{
					// По всей видимости дурит консоль Windows.
					// Если в буфере сейчас еще есть мышиные события, то запись
					// в буфер возвращает ОК, но считывающее приложение получает 0-событий.
					// В итоге, получаем пропуск некоторых событий, что очень неприятно 
					// при выделении кучи файлов правой кнопкой мыши (проводкой с зажатой кнопкой)
					if (pr[n].Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
						lbReqEmpty = TRUE;
				}
			}

			pr = prNew;
			_ASSERTE(nAllCount == (ppr-prNew));
			nCount = (UINT)(ppr-prNew);
		}
	}

	// Если не готов - все равно запишем
	WaitConsoleReady(lbReqEmpty);


	DWORD cbWritten = 0;

#ifdef _DEBUG
	wchar_t szDbg[255];
	for (UINT i = 0; i < nCount; i++)
	{
		if (pr[i].EventType == MOUSE_EVENT)
		{
			_wsprintf(szDbg, SKIPLEN(countof(szDbg))
				L"*** ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n",
				pr[i].Event.MouseEvent.dwMousePosition.X, pr[i].Event.MouseEvent.dwMousePosition.Y, pr[i].Event.MouseEvent.dwButtonState, (pr[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED));
			DEBUGSTRINPUTWRITE(szDbg);
			
			#ifdef _DEBUG
			{
				static int LastMsButton;
				if ((LastMsButton & 1) && (pr[i].Event.MouseEvent.dwButtonState == 0))
				{
					// LButton was Down, now - Up
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
				else if (!LastMsButton && (pr[i].Event.MouseEvent.dwButtonState & 1))
				{
					// LButton was Up, now - Down
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
				else
				{ //-V523
					LastMsButton = pr[i].Event.MouseEvent.dwButtonState;
				}
			}
			#endif
			
		}
	}
	SetLastError(0);
#endif


	HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); // тут был ghConIn
	fSuccess = WriteConsoleInput(hIn, pr, nCount, &cbWritten);


#ifdef _DEBUG
	DWORD dwErr = GetLastError();
	if (!fSuccess || (nCount != cbWritten))
	{
		_wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"### WriteConsoleInput(Write=%i, Written=%i, Left=%i, Err=x%X)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents(), dwErr);
		DEBUGSTRINPUTWRITEFAIL(szDbg);
	}
	else
	{
		_wsprintf(szDbg, SKIPLEN(countof(szDbg)) L"*** WriteConsoleInput(Write=%i, Written=%i, Left=%i)\n", nCount, cbWritten, gpSrv->InputQueue.GetNumberOfBufferEvents());
		DEBUGSTRINPUTWRITEALL(szDbg);
	}
#endif
	_ASSERTE(fSuccess && cbWritten==nCount);

	if (prNew) free(prNew);

	return fSuccess;
}