Использование высокоуровневых функций ввода и вывода
Нижеследующий пример использует высокоуровневые консольные функции I/O для консольного ввода - вывода. Для получения дополнительной информации о высокоуровневых консольных функциях I/O, см. статью Высокоуровневый консольный ввод - вывод I/O).
В примере предполагается, что заданные по умолчанию режимы ввода - вывода (I/O) являются по существу вначале для первого вызова функций ReadFile и WriteFile. Затем для второго вызова ReadFile и WriteFile режим ввода данных изменяется, выключается режим построчного ввода данных и отраженный режим ввода данных. Функция SetConsoleTextAttribute используется для, установки цвета, которым впоследствии письменный текст будет показан на экране. Перед выходом, программа восстанавливает исходный консольный режим ввода данных и атрибуты цвета.
Функция NewLine примера используется тогда, когда отключается режим построчного ввода данных. Она обрабатывает возвраты каретки, перемещая позицию курсора в первую ячейку следующей строки. Если курсор находится уже в последней строке экранного буфера консоли, содержание экранного буфера консоли прокручивается вверх на одну строку.
Обратите внимание! на то, что MyErrorExit - групповой символ - заместитель для определяемой программой функции, которая показывает на экране и обрабатывает аварийные ситуации. |
#include <windows.h> void NewLine(void); void ScrollScreenBuffer(HANDLE, INT); HANDLE hStdout, hStdin; CONSOLE_SCREEN_BUFFER_INFO csbiInfo; void main(void) { LPSTR lpszPrompt1 = "Type a line and press Enter, or q to quit: "; LPSTR lpszPrompt2 = "Type any key, or q to quit: "; CHAR chBuffer[256]; DWORD cRead, cWritten, fdwMode, fdwOldMode; WORD wOldColorAttrs; // Получим дескрипторы для STDIN и STDOUT. hStdin = GetStdHandle(STD_INPUT_HANDLE); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) { MessageBox(NULL, "GetStdHandle", "Console Error", MB_OK); return; } // Сохраним текущий цвет текста. if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK); return; } wOldColorAttrs = csbiInfo.wAttributes; // Установим атрибуты текста которые пишут красный текст по черному фону. if (! SetConsoleTextAttribute(hStdout, FOREGROUND_RED|FOREGROUND_INTENSITY)) { MessageBox(NULL, "SetConsoleTextAttribute", "Console Error", MB_OK); return; } // Запишем в STDOUT и прочитаем из STDIN, используя режим по умолчанию. // При вводе данных эхо-режим осуществляется автоматически, а функция ReadFile // не возвращает значения до тех пор, пока не напечатается каретка возврата. // // Режим ввода по умолчанию - построчный, обрабатываемый и эхо-режим. // Режим вывода по умолчанию - обрабатываемый и с автопереносом в конце строки EOL. while (1) { if (! WriteFile( hStdout, // дескриптор вывода lpszPrompt1, // строка приглашения к вводу lstrlen(lpszPrompt1), // длина строки &cWritten, // записано байтов NULL) ) // не перекрывающееся { MessageBox(NULL, "WriteFile", "Console Error", MB_OK); return; } if (! ReadFile( hStdin, // дескриптор ввода chBuffer, // буфер для передачи 255, // размер буфера &cRead, // действительно прочитанные байты NULL) ) // не перекрывающееся break; if (chBuffer[0] == 'q') break; } // Выключим построчный режим ввода и эхо-режим. if (! GetConsoleMode(hStdin, &fdwOldMode)) { MessageBox(NULL, "GetConsoleMode", "Console Error", MB_OK); return; } fdwMode = fdwOldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); if (! SetConsoleMode(hStdin, fdwMode)) { MessageBox(NULL, "SetConsoleMode", "Console Error", MB_OK); return; } // Без эхо-режима и построчного ввода, ReadFile возвращает значение, // когда доступен какой либо ввод данных. Возврат каретки должен // обрабатываться, а WriteFile используется в эхо-режиме для ввода данных. NewLine(); while (1) { if (! WriteFile( hStdout, // дескриптор вывода lpszPrompt2, // строка приглашения к вводу lstrlen(lpszPrompt2), // длина строки &cWritten, // записано байтов NULL) ) // не перекрывающееся { MessageBox(NULL, "WriteFile", "Console Error", MB_OK); return; } if (! ReadFile(hStdin, chBuffer, 1, &cRead, NULL)) break; if (chBuffer[0] == '\r') NewLine(); else if (! WriteFile(hStdout, chBuffer, cRead, &cWritten, NULL)) break; else NewLine(); if (chBuffer[0] == 'q') break; } // Восстанавливаем исходный режим консоли. SetConsoleMode(hStdin, fdwOldMode); // Восстанавливаем исходный режим текста. SetConsoleTextAttribute(hStdout, wOldColorAttrs); } // Функция NewLine обрабатывает возврат каретки тогда, когда режим обработки // вводимых данных отключается. Она получает текущую позицию курсора // и сбрасывает ее до позиции первой ячейки следующей строки. void NewLine(void) { if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) { MessageBox(NULL, "GetConsoleScreenBufferInfo", "Console Error", MB_OK); return; } csbiInfo.dwCursorPosition.X = 0; // Если это последняя строка в буфере экрана, прокручивает буфер вверх. if ((csbiInfo.dwSize.Y-1) == csbiInfo.dwCursorPosition.Y) { ScrollScreenBuffer(hStdout, 1); } // Иначе, продвигает вперед курсор к следующей строке else csbiInfo.dwCursorPosition.Y += 1; if (! SetConsoleCursorPosition(hStdout, csbiInfo.dwCursorPosition)) { MessageBox(NULL, "SetConsoleCursorPosition", "Console Error", MB_OK); return; } } void ScrollScreenBuffer(HANDLE h, INT x) { SMALL_RECT srctScrollRect, srctClipRect; CHAR_INFO chiFill; COORD coordDest; srctScrollRect.Left = 0; srctScrollRect.Top = 1; srctScrollRect.Right = csbiInfo.dwSize.X - x; srctScrollRect.Bottom = csbiInfo.dwSize.Y - x; // Назначение для прямоугольника прокрутки - одна строка вверх coordDest.X = 0; coordDest.Y = 0; // Прямоугольник отсечения по границам тот же самый, что и прокручивающийся прямоугольник. // Строка назначения оставлена неизменной srctClipRect = srctScrollRect; // Установим символ - заполнитель и атрибуты chiFill.Attributes = FOREGROUND_RED|FOREGROUND_INTENSITY; chiFill.Char.AsciiChar = ' '; // Прокрутим вверх на одну строку. ScrollConsoleScreenBuffer( h, // дескриптор экранного буфера &srctScrollRect, // прямоугольник прокрутки &srctClipRect, // прямоугольник отсечения coordDest, // верхняя левая ячейка назначения &chiFill); // символ-заполнитель и цвет } |