BOOL ProcessInputMessage(MSG64::MsgStr &msg, INPUT_RECORD &r) { memset(&r, 0, sizeof(r)); BOOL lbOk = FALSE; if (!UnpackInputRecord(&msg, &r)) { _ASSERT(FALSE); } else { TODO("Сделать обработку пачки сообщений, вдруг они накопились в очереди?"); //#ifdef _DEBUG //if (r.EventType == KEY_EVENT && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL)) //{ // DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); //} //#endif bool lbProcessEvent = false; bool lbIngoreKey = false; if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) && ( // Удерживается ТОЛЬКО Ctrl (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((r.Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS)) ) ) { lbProcessEvent = true; DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); DWORD dwMode = 0; GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwMode); // CTRL+C (and Ctrl+Break?) is processed by the system and is not placed in the input buffer if ((dwMode & ENABLE_PROCESSED_INPUT) == ENABLE_PROCESSED_INPUT) lbIngoreKey = lbProcessEvent = true; else lbProcessEvent = false; if (lbProcessEvent) { //BOOL lbRc = FALSE; #if 0 DWORD dwEvent = (r.Event.KeyEvent.wVirtualKeyCode == 'C') ? CTRL_C_EVENT : CTRL_BREAK_EVENT; #endif //&& (gpSrv->dwConsoleMode & ENABLE_PROCESSED_INPUT) #if 1 // Issue 590: GenerateConsoleCtrlEvent нифига не прерывает функцию ReadConsoleW SendMessage(ghConWnd, WM_KEYDOWN, r.Event.KeyEvent.wVirtualKeyCode, 0); //lbRc = TRUE; #endif #if 0 //The SetConsoleMode function can disable the ENABLE_PROCESSED_INPUT mode for a console's input buffer, //so CTRL+C is reported as keyboard input rather than as a signal. // CTRL+BREAK is always treated as a signal if ( // Удерживается ТОЛЬКО Ctrl (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((r.Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS)) ) { // Вроде работает, Главное не запускать процесс с флагом CREATE_NEW_PROCESS_GROUP // иначе у микрософтовской консоли (WinXP SP3) сносит крышу, и она реагирует // на Ctrl-Break, но напрочь игнорирует Ctrl-C lbRc = GenerateConsoleCtrlEvent(dwEvent, 0); // Это событие (Ctrl+C) в буфер помещается(!) иначе до фара не дойдет собственно клавиша C с нажатым Ctrl } #endif } if (lbIngoreKey) return FALSE; // CtrlBreak отсылаем СРАЗУ, мимо очереди, иначе макросы FAR нельзя стопнуть if (r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) { // При получении CtrlBreak в реальной консоли - буфер ввода очищается // иначе фар, при попытке считать ввод получит старые, // еще не обработанные нажатия, и CtrlBreak проигнорирует FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); SendConsoleEvent(&r, 1); return FALSE; } } #ifdef _DEBUG if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && r.Event.KeyEvent.wVirtualKeyCode == VK_F11) { DEBUGSTR(L" --- F11 recieved\n"); } #endif #ifdef _DEBUG if (r.EventType == MOUSE_EVENT) { static DWORD nLastEventTick = 0; if (nLastEventTick && (GetTickCount() - nLastEventTick) > 2000) { OutputDebugString(L".\n"); } wchar_t szDbg[60]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L" ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", r.Event.MouseEvent.dwMousePosition.X, r.Event.MouseEvent.dwMousePosition.Y, r.Event.MouseEvent.dwButtonState, (r.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGLOGINPUT(szDbg); nLastEventTick = GetTickCount(); } #endif // Запомнить, когда была последняя активность пользователя if (r.EventType == KEY_EVENT || (r.EventType == MOUSE_EVENT && (r.Event.MouseEvent.dwButtonState || r.Event.MouseEvent.dwEventFlags || r.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))) { gpSrv->dwLastUserTick = GetTickCount(); } lbOk = TRUE; //SendConsoleEvent(&r, 1); } return lbOk; }
DWORD WINAPI InputThread(LPVOID lpvParam) { HANDLE hEvents[2] = {ghQuitEvent, gpSrv->hInputEvent}; DWORD dwWait = 0; INPUT_RECORD ir[100]; while ((dwWait = WaitForMultipleObjects(2, hEvents, FALSE, INPUT_QUEUE_TIMEOUT)) != WAIT_OBJECT_0) { if (gpSrv->InputQueue.IsInputQueueEmpty()) continue; // -- перенесено в SendConsoleEvent //// Если не готов - все равно запишем //if (!WaitConsoleReady()) // break; // Читаем и пишем DWORD nInputCount = sizeof(ir)/sizeof(ir[0]); //#ifdef USE_INPUT_SEMAPHORE //DWORD nSemaphore = ghConInSemaphore ? WaitForSingleObject(ghConInSemaphore, INSEMTIMEOUT_WRITE) : 1; //_ASSERTE(ghConInSemaphore && (nSemaphore == WAIT_OBJECT_0)); //#endif InputLogger::Log(InputLogger::Event::evt_ReadInputQueue); if (gpSrv->InputQueue.ReadInputQueue(ir, &nInputCount)) { _ASSERTE(nInputCount>0); // Выставить флаг, что прошло очередное чтение InputLogger::Log(InputLogger::Event::evt_SetEvent, nInputCount); SetEvent(gpSrv->hInputWasRead); #ifdef _DEBUG for(DWORD j = 0; j < nInputCount; j++) { if (ir[j].EventType == KEY_EVENT && (ir[j].Event.KeyEvent.wVirtualKeyCode == 'C' || ir[j].Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) && ( // Удерживается ТОЛЬКО Ctrl (ir[j].Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((ir[j].Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (ir[j].Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS))) ) { DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); } } #endif // Write InputLogger::Log(InputLogger::Event::evt_SendStart, nInputCount); //DEBUGSTRINPUTPIPE(L"SendConsoleEvent\n"); SendConsoleEvent(ir, nInputCount); InputLogger::Log(InputLogger::Event::evt_SendEnd, nInputCount); } //#ifdef USE_INPUT_SEMAPHORE //if ((nSemaphore == WAIT_OBJECT_0) && ghConInSemaphore) ReleaseSemaphore(ghConInSemaphore, 1, NULL); //#endif // Если во время записи в консоль в буфере еще что-то появилось - передернем if (!gpSrv->InputQueue.IsInputQueueEmpty()) SetEvent(gpSrv->hInputEvent); } return 1; }
BOOL ProcessInputMessage(MSG64::MsgStr &msg, INPUT_RECORD &r) { memset(&r, 0, sizeof(r)); BOOL lbOk = FALSE; if (!UnpackInputRecord(&msg, &r)) { _ASSERT(FALSE); } else { TODO("Сделать обработку пачки сообщений, вдруг они накопились в очереди?"); //#ifdef _DEBUG //if (r.EventType == KEY_EVENT && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL)) //{ // DEBUGSTR(L" --- CtrlC/CtrlBreak recieved\n"); //} //#endif bool lbProcessEvent = false; bool lbIngoreKey = false; if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && (r.Event.KeyEvent.wVirtualKeyCode == 'C' || r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) && ( // Удерживается ТОЛЬКО Ctrl (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS) && ((r.Event.KeyEvent.dwControlKeyState & ALL_MODIFIERS) == (r.Event.KeyEvent.dwControlKeyState & CTRL_MODIFIERS)) ) ) { wchar_t szLog[100]; lbProcessEvent = true; LogString(L" --- CtrlC/CtrlBreak recieved"); DWORD dwMode = 0; GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwMode); // CTRL+C (and Ctrl+Break?) is processed by the system and is not placed in the input buffer if ((dwMode & ENABLE_PROCESSED_INPUT) == ENABLE_PROCESSED_INPUT) lbIngoreKey = lbProcessEvent = true; else lbProcessEvent = false; if (RELEASEDEBUGTEST((gpLogSize!=NULL),true)) { bool bAlt = isPressed(VK_MENU), bShift = isPressed(VK_SHIFT), bCtrl = isPressed(VK_CONTROL); if (bAlt || bShift || !bCtrl) { msprintf(szLog, countof(szLog), L" --- CtrlC/CtrlBreak may fails because of bad Alt/Shift/Ctrl state (%u,%u,%u)!", (UINT)bAlt, (UINT)bShift, (UINT)bCtrl); LogString(szLog); } if (!lbProcessEvent) { LogString(L" --- CtrlC/CtrlBreak may fails because of disabled ENABLE_PROCESSED_INPUT!"); } } if (lbProcessEvent) { // Issue 590: GenerateConsoleCtrlEvent does not break ReadConsole[A|W] function! SetLastError(0); LRESULT lSendRc = SendMessage(ghConWnd, WM_KEYDOWN, r.Event.KeyEvent.wVirtualKeyCode, 0); DWORD nErrCode = GetLastError(); msprintf(szLog, countof(szLog), L" --- CtrlC/CtrlBreak sent (%u,%u)", LODWORD(lSendRc), nErrCode); LogString(szLog); } if (lbIngoreKey) return FALSE; // In the real console, when CtrlBreak is received, input buffer is cleared. // Otherwise, in Far Manager for example, it's impossible to stop some operation, // it will try to peek old data and CtrlBreak may be left unread if (r.Event.KeyEvent.wVirtualKeyCode == VK_CANCEL) { LogString(L" --- VK_CANCEL received, flushing, sending..."); FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); SendConsoleEvent(&r, 1); return FALSE; } } #ifdef _DEBUG if (r.EventType == KEY_EVENT && r.Event.KeyEvent.bKeyDown && r.Event.KeyEvent.wVirtualKeyCode == VK_F11) { LogString(L" --- F11 recieved\n"); } #endif #ifdef _DEBUG if (r.EventType == MOUSE_EVENT) { static DWORD nLastEventTick = 0; if (nLastEventTick && (GetTickCount() - nLastEventTick) > 2000) { OutputDebugString(L".\n"); } wchar_t szDbg[60]; _wsprintf(szDbg, SKIPLEN(countof(szDbg)) L" ConEmuC.MouseEvent(X=%i,Y=%i,Btns=0x%04x,Moved=%i)\n", r.Event.MouseEvent.dwMousePosition.X, r.Event.MouseEvent.dwMousePosition.Y, r.Event.MouseEvent.dwButtonState, (r.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)); DEBUGLOGINPUT(szDbg); nLastEventTick = GetTickCount(); } #endif // Запомнить, когда была последняя активность пользователя if (r.EventType == KEY_EVENT || (r.EventType == MOUSE_EVENT && (r.Event.MouseEvent.dwButtonState || r.Event.MouseEvent.dwEventFlags || r.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))) { gpSrv->dwLastUserTick = GetTickCount(); } lbOk = TRUE; //SendConsoleEvent(&r, 1); } return lbOk; }