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; }
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; }