int uv_tty_read_stop(uv_tty_t* handle) { handle->flags &= ~UV_HANDLE_READING; /* Cancel raw read */ if ((handle->flags & UV_HANDLE_READ_PENDING) && (handle->flags & UV_HANDLE_TTY_RAW)) { /* Write some bullshit event to force the console wait to return. */ INPUT_RECORD record; DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { uv_set_sys_error(handle->loop, GetLastError()); return -1; } } /* Cancel line-buffered read */ if (handle->read_line_handle != NULL) { /* Closing this handle will cancel the ReadConsole operation */ CloseHandle(handle->read_line_handle); handle->read_line_handle = NULL; } return 0; }
void SendKeyHelper(HANDLE hIn, WORD vk) { INPUT_RECORD irPause = { 0 }; irPause.EventType = KEY_EVENT; irPause.Event.KeyEvent.bKeyDown = TRUE; irPause.Event.KeyEvent.wVirtualKeyCode = vk; DWORD dwWritten = 0; VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInputW(hIn, &irPause, 1u, &dwWritten), L"Key event sent."); }
void WriteConsoleKey(HANDLE console,DWORD Key,DWORD State) { INPUT_RECORD event; DWORD written; event.EventType=KEY_EVENT; event.Event.KeyEvent.bKeyDown=TRUE; event.Event.KeyEvent.wRepeatCount=1; event.Event.KeyEvent.wVirtualKeyCode=(WORD)Key; event.Event.KeyEvent.wVirtualScanCode=0; event.Event.KeyEvent.uChar.UnicodeChar=0; event.Event.KeyEvent.dwControlKeyState=State; WriteConsoleInputW(console,&event,1,&written); }
static PyObject * _testconsole_write_input_impl(PyObject *module, PyObject *file, PyBytesObject *s) /*[clinic end generated code: output=48f9563db34aedb3 input=4c774f2d05770bc6]*/ { INPUT_RECORD *rec = NULL; if (!PyWindowsConsoleIO_Check(file)) { PyErr_SetString(PyExc_TypeError, "expected raw console object"); return NULL; } const wchar_t *p = (const wchar_t *)PyBytes_AS_STRING(s); DWORD size = (DWORD)PyBytes_GET_SIZE(s) / sizeof(wchar_t); rec = (INPUT_RECORD*)PyMem_Malloc(sizeof(INPUT_RECORD) * size); if (!rec) goto error; memset(rec, 0, sizeof(INPUT_RECORD) * size); INPUT_RECORD *prec = rec; for (DWORD i = 0; i < size; ++i, ++p, ++prec) { prec->EventType = KEY_EVENT; prec->Event.KeyEvent.bKeyDown = TRUE; prec->Event.KeyEvent.wRepeatCount = 10; prec->Event.KeyEvent.uChar.UnicodeChar = *p; } HANDLE hInput = ((winconsoleio*)file)->handle; DWORD total = 0; while (total < size) { DWORD wrote; if (!WriteConsoleInputW(hInput, &rec[total], (size - total), &wrote)) { PyErr_SetFromWindowsErr(0); goto error; } total += wrote; } PyMem_Free((void*)rec); Py_RETURN_NONE; error: if (rec) PyMem_Free((void*)rec); return NULL; }
BOOL OnExecutePromptCmd(LPCWSTR asCmd) { if (!gReadConsoleInfo.InReadConsoleTID && !gReadConsoleInfo.LastReadConsoleInputTID) return FALSE; HANDLE hConIn = gReadConsoleInfo.InReadConsoleTID ? gReadConsoleInfo.hConsoleInput : gReadConsoleInfo.hConsoleInput2; if (!hConIn) return FALSE; BOOL lbRc = FALSE; INPUT_RECORD r[256]; INPUT_RECORD* pr = r; INPUT_RECORD* prEnd = r + countof(r); LPCWSTR pch = asCmd; DWORD nWrite, nWritten; BOOL lbWrite; while (*pch) { // Если (\r\n)|(\n) - слать \r if ((*pch == L'\r') || (*pch == L'\n')) { TranslateKeyPress(0, 0, L'\r', -1, pr, pr+1); if (*pch == L'\r' && *(pch+1) == L'\n') pch += 2; else pch ++; } else { TranslateKeyPress(0, 0, *pch, -1, pr, pr+1); pch ++; } pr += 2; if (pr >= prEnd) { _ASSERTE(pr == prEnd); if (pr && (pr > r)) { nWrite = (DWORD)(pr - r); lbWrite = WriteConsoleInputW(hConIn, r, nWrite, &nWritten); if (!lbWrite) { pr = NULL; lbRc = FALSE; break; } if (*pch) // Чтобы не было переполнения буфера Sleep(10); lbRc = TRUE; } pr = r; } } if (pr && (pr > r)) { nWrite = (DWORD)(pr - r); lbRc = WriteConsoleInputW(hConIn, r, nWrite, &nWritten); } return lbRc; }
// 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; }
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; }