参考文章如下:
https://www.cnblogs.com/lxl0928/p/3807262.html
https://www.cnblogs.com/tocy/p/Console-Introduction.html
https://www.cnblogs.com/tocy/p/console_intro_sample.html
https://www.cnblogs.com/tocy/p/console_io_function_intro.html
https://blog.csdn.net/gzzheyi/article/details/7190143
https://blog.csdn.net/ccfxue/article/details/52788199
https://zhidao.baidu.com/question/304673144230099084.html
注意:
本文主要将个人认为常用或重要的知识整合成文,有所省略。
更多详情内容,有意请前往上述参考文章。
HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输入设备句柄
HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); //获取标准输入设备句柄
INPUT_RECORD inRec;//设置获取事件的变量
DWORD numRead; //返回已读取的记录数
ReadConsoleInput(hInput, &inRec, 1, &numRead); //读取1个输入事件//这是一个非阻塞的函数
CreateConsoleScreenBuffer函数为控制台创建新的屏幕缓冲。
SetConsoleActiveScreenBuffer 函数将屏幕缓冲设置为活动屏幕缓冲,达到显示的目的。
不管是什么类型的屏幕缓冲(活动或者非活动)都可以直接读写。
GetConsoleCursorInfo 获取光标外观及显示或隐藏属性。
SetConsoleCursorInfo 设置光标外观及显示或隐藏属性。
SetConsoleCursorPosition 设置屏幕缓冲的光标位置
GetConsoleSelectionInfo 获取控制台中实际选择的字符区域和位置
GetConsoleScreenBufferInfo 获取窗口大小、屏幕缓冲大小和颜色属性,光标位置,屏幕缓冲字符属性,屏幕缓冲窗口RECT
SetConsoleWindowInfo 设置控制台位置及大小。
注意调整活动屏幕缓冲的窗口大小会影响实际显示的控制台窗口大小。
SetConsoleScreenBufferSize 设置控制台屏幕缓冲大小。
其不会触发缓冲区缩放事件
使用它必须保证设置的屏幕缓冲大小不小于屏幕缓冲窗口大小。
SetConsoleTextAttribute 设置控制台字符属性
GetCurrentConsoleFont 获取控制台当前显示的字体属性可以通过函数
SetConsoleTitle 设置控制台标题
GetConsoleTitle 获取控制台标题
GetConsoleMode 获取控制台模式
SetConsoleMode 设置控制台模式
控制台在创建时会默认启用以下输入模式:
行输入模式(ENABLE_LINE_INPUT)
自动处理输入模式(ENABLE_PROCESSED_INPUT)
输入回显模式(ENABLE_ECHO_INPUT)
自动启用以下输出模式:
自动处理输出模式(ENABLE_PROCESSED_OUTPUT)
自动换行模式(ENABLE_WRAP_AT_EOL_OUTPUT)
其余模式描述:
ENABLE_PROCESSED_INPUT。 自动处理输入模式,用于控制是否将系统控制键及系统事件放到输出缓冲中。
ENABLE_LINE_INPUT。 自动换行模式。用于控制台输入函数响应方式。
ENABLE_ECHO_INPUT。 输入回显模式
ENABLE_PROCESSED_OUTPUT。 自动处理输出模式
ENABLE_WRAP_AT_EOL_OUTPUT。 输出自动换行模式
ENABLE_MOUSE_INPUT。 使能鼠标输入
ENABLE_WINDOW_INPUT。 用于控制是否在输入缓冲中记录窗口缩放事件。
ENABLE_PROCESSED_INPUT。 用于控制高层控制台输入输出函数。
高层控制台I/O仅有四个函数:ReadFile和WriteFile 、ReadConsole和WriteConsole。
这两组函数功能相似,主要有两个区别。
- -ReadConsole和WriteConsole函数支持ANSI和UNICODE;
-ReadFile和WriteFile函数仅支持ANSI。 - -ReadFile和WriteFile函数支持文件、管道、串口通信等机制;
- ReadConsole和WriteConsole函数仅支持控制台句柄,不能使用重定向之后的句柄。
对于需要重定向输入输出的应用建议慎重选择。
函数介绍:
ReadConsoleInput 从输入缓冲中读取并移除输入记录
PeekConsoleInput 从输入缓冲中读取输入记录,但不移除输入记录
GetNumberOfConsoleInputEvents 获取输入缓冲中未读取的输入记录的个数
WriteConsoleInput 在输入缓冲尾部添加一个新的输入记录
FlushConsoleInputBuffer 清空输入缓冲中所有的输入记录
底层输出函数
底层输出函数可以直接访问控制台屏幕缓冲的字符。主要包含以下几个函数:
ReadConsoleOutputCharacter 从屏幕缓冲中读入ANSI或UNICODE字符串。
WriteConsoleOutputCharacter 向屏幕缓冲中写入ANSI或UNICODE字符串。
ReadConsoleOutputAttribute 从屏幕缓冲中复制包含文本属性的字符串。
WriteConsoleOutputAttribute 向屏幕缓冲中写入包含文本属性的字符串。
FillConsoleOutputCharacter 向屏幕缓冲中连续写入多个ANSI或UNICODE字符。
FillConsoleOutputAttribute 向屏幕缓冲中连续写入多个包含文本属性的字符。
ReadConsoleOutput 从屏幕缓冲中读取指定区域的字符(包含文本属性)。
WriteConsoleOutput 向屏幕缓冲中写入指定区域的字符(包含文本属性)。
上面函数中读取指定区域的函数,把屏幕缓冲、源缓冲、目标缓冲当成是由CHAR_INFO结构构成的二维数组,
区域以字符宽度为单位长度,区域使用SMALL_RECT结构体标记。
CTRL+C组合键可以通过以下方式修改控制台的响应处理:
使用函数SetConsoleMode禁用ENABLE_PROCESSED_INPUT输入模式,可以让系统把CTRL+C作为键盘输入而不是终止信号。
使用SetConsoleCtrlHandler 函数可让程序忽略CTRL+C的终止信号。
下面展示相关结构体以及对应事件常量:
COORD pos = {0,0};//设置坐标类
pos = inRec.Event.MouseEvent.dwMousePosition;//获取鼠标位置
typedef struct _KEY_EVENT_RECORD {//键盘事件
BOOL bKeyDown; // 键位是被按下还是释放
WORD wRepeatCount; // 重复按键次数,大于1表示键位被按下未释放
WORD wVirtualKeyCode; // 设备无关的虚拟键码
WORD wVirtualScanCode; // 设备相关的虚拟扫描码
union { // 转换后的ASCII码或者UNICODE码
WCHAR UnicodeChar;
CHAR AsciiChar;
} uChar;
DWORD dwControlKeyState; // 控制键状态,ctrl、shift、alt、caps Lock等
}KEY_EVENT_RECORD,*PKEY_EVENT_RECORD;
//
// ControlKeyState flags
//
#define RIGHT_ALT_PRESSED 0x0001 // 键盘右Alt键被按
#define LEFT_ALT_PRESSED 0x0002 // 键盘左Alt键被按
#define RIGHT_CTRL_PRESSED 0x0004 // 键盘右Ctrl键被按
#define LEFT_CTRL_PRESSED 0x0008 // 键盘左Ctrl键被按
#define SHIFT_PRESSED 0x0010 // 键盘Shift键被按
#define NUMLOCK_ON 0x0020 // 数字锁定被打开
#define SCROLLLOCK_ON 0x0040 // 滚动锁定被打开
#define CAPSLOCK_ON 0x0080 // 大写锁定被打开
#define ENHANCED_KEY 0x0100 // the key is enhanced.//经查找,得知是万国商业机器公司的键盘.属于硬件普通101键或102键
#define NLS_DBCSCHAR 0x00010000 // DBCS for JPN: SBCS/DBCS mode.
#define NLS_ALPHANUMERIC 0x00000000 // DBCS for JPN: Alphanumeric mode.
#define NLS_KATAKANA 0x00020000 // DBCS for JPN: Katakana mode.
#define NLS_HIRAGANA 0x00040000 // DBCS for JPN: Hiragana mode.
#define NLS_ROMAN 0x00400000 // DBCS for JPN: Roman/Noroman mode.
#define NLS_IME_CONVERSION 0x00800000 // DBCS for JPN: IME conversion.
#define ALTNUMPAD_BIT 0x04000000 // AltNumpad OEM char (copied from ntuser\inc\kbd.h) ;internal_NT
#define NLS_IME_DISABLE 0x20000000 // DBCS for JPN: IME enable/disable.
typedef struct _MOUSE_EVENT_RECORD {//鼠标事件
COORD dwMousePosition; // 基于字符的屏幕坐标位置
DWORD dwButtonState; // 鼠标按键标志
DWORD dwControlKeyState; // 控制键状态标志
DWORD dwEventFlags; // 鼠标事件标志,单击、双击、按下、弹起、鼠标移动、滚轮事件
} MOUSE_EVENT_RECORD,*PMOUSE_EVENT_RECORD;
//
// ButtonState flags
//
#define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001//最左边按键,理解为鼠标左键单击
#define RIGHTMOST_BUTTON_PRESSED 0x0002//最右边按键,理解为鼠标右键单击
#define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004//左起第二个按键
#define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008//左起第三个按键
#define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010//左起第四个按键
//
// EventFlags
//
#define MOUSE_MOVED 0x0001//移动
#define DOUBLE_CLICK 0x0002//双击
#define MOUSE_WHEELED 0x0004//滚轮滚动->垂直鼠标滚轮滚动
#if(_WIN32_WINNT >= 0x0600)//如果系统版本高于Windows Server 2008
#define MOUSE_HWHEELED 0x0008//水平鼠标滚轮移动
#endif /* _WIN32_WINNT >= 0x0600 */
typedef struct _INPUT_RECORD {//输入事件:用来存储获得的事件
WORD EventType;//事件类型
union {
KEY_EVENT_RECORD KeyEvent; //键盘信息
MOUSE_EVENT_RECORD MouseEvent; //鼠标信息
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;//窗口变更信息
MENU_EVENT_RECORD MenuEvent; //菜单信息
FOCUS_EVENT_RECORD FocusEvent; //焦点信息
} Event;//一个共用体成员变量
} INPUT_RECORD, *PINPUT_RECORD;
//
// EventType flags:
//
KEY_EVENT 0x0001 //键盘事件
MOUSE_EVENT 0x0002 //鼠标事件
WINDOW_BUFFER_SIZE_EVENT 0x0004 //窗口变更事件
MENU_EVENT 0x0008 //菜单事件
FOCUS_EVENT 0x0010 //焦点变更事件
typedef struct _WINDOW_BUFFER_SIZE_RECORD {//缓冲区缩放事件
COORD dwSize;
} WINDOW_BUFFER_SIZE_RECORD, *PWINDOW_BUFFER_SIZE_RECORD;
typedef struct _MENU_EVENT_RECORD {//屏幕事件
UINT dwCommandId;
} MENU_EVENT_RECORD, *PMENU_EVENT_RECORD;
typedef struct _FOCUS_EVENT_RECORD {//焦点事件
BOOL bSetFocus;
} FOCUS_EVENT_RECORD, *PFOCUS_EVENT_RECORD;
typedef struct _CHAR_INFO {//屏幕中单个元素的信息
union {//显示字符
WCHAR UnicodeChar;
CHAR AsciiChar;
} Char;
WORD Attributes;//字符前景色,背景色
} CHAR_INFO, *PCHAR_INFO;
typedef struct _CONSOLE_FONT_INFO {//字体属性设置
DWORD nFont; //系统默认字体索引
COORD dwFontSize; //字符大小,宽x高
} CONSOLE_FONT_INFO, *PCONSOLE_FONT_INFO;
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {//屏幕缓冲信息和窗口信息
COORD dwSize; // 缓冲区大小
COORD dwCursorPosition; // 当前光标位置
WORD wAttributes; // 字符属性
SMALL_RECT srWindow; // 当前窗口显示的大小和位置
COORD dwMaximumWindowSize; // 最大的窗口缓冲区大小
} CONSOLE_SCREEN_BUFFER_INFO, *PCONSOLE_SCREEN_BUFFER_INFO;
最后,附上一个可执行实例:
#include <Windows.h>
#include <iostream>
using std::wcout;//开放宽字节输出流
using std::endl;//开放回车
int main() {
std::wcout.imbue(std::locale("chs"));//设置为中文输出
HANDLE stdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE); /* 获取标准输入设备句柄 */
HANDLE stdInHandle = GetStdHandle(STD_INPUT_HANDLE); /* 获取标准输入设备句柄 */
DWORD numRead; /* 返回已读取的记录数 */
INPUT_RECORD inRec;//输入事件-它的成员就包含了下列5类事件,一般只需要定义这个,无需独立定义五个
KEY_EVENT_RECORD keyEveRec;//键盘事件
MOUSE_EVENT_RECORD mouEveRec;//鼠标事件
WINDOW_BUFFER_SIZE_RECORD winBufSizRec;//缓冲区缩放事件
MENU_EVENT_RECORD menEveRec;//屏幕事件
FOCUS_EVENT_RECORD focEveRec;//焦点事件
CHAR_INFO charIn;//屏幕中单个元素的信息
CONSOLE_FONT_INFO conFontIn;//字体属性
CONSOLE_SCREEN_BUFFER_INFO conScrBufIn;//屏幕缓冲大小
DWORD title_need_size = 256;//标题文本最大可存储长度
//SetConsoleMode(stdInHandle, ENABLE_MOUSE_INPUT);//使得能够获得鼠标输入
//SetConsoleMode(stdInHandle, ENABLE_WINDOW_INPUT);//使得能够获取窗口缩放事件
/*其余模式描述
ENABLE_PROCESSED_INPUT。自动处理输入模式,用于控制是否将系统控制键及系统事件放到输出缓冲中。
ENABLE_LINE_INPUT。自动换行模式。用于控制台输入函数响应方式。
ENABLE_ECHO_INPUT。输入回显模式
ENABLE_PROCESSED_OUTPUT。自动处理输出模式
ENABLE_WRAP_AT_EOL_OUTPUT。输出自动换行模式
ENABLE_MOUSE_INPUT。使能鼠标输入
ENABLE_WINDOW_INPUT。用于控制是否在输入缓冲中记录窗口缩放事件。
ENABLE_PROCESSED_INPUT。用于控制高层控制台输入输出函数。
详情:https://www.cnblogs.com/tocy/p/console_io_function_intro.html
*/
TCHAR * console_title = new TCHAR[title_need_size + 1];//获取用来存储标题文本的内存指针
memset(console_title, 0, (title_need_size + 1) * sizeof(TCHAR));
//以0为值将该内存块(console_title)中的((title_need_size + 1) * sizeof(TCHAR))个字节给初始化
DWORD title_size = GetConsoleTitle(console_title, title_need_size);//获取控制台标题
if (0 == title_size)//判断获取控制台标题是否出错
{
wcout << "调用GetConsoleTitle异常,错误码" << GetLastError() << endl;
//GetLastError()输出返回的错误码
delete[] console_title;//释放内存
return 0;//异常退出程序
}
wcout << "控制台标题栏" << console_title << endl;
SetConsoleTitle(TEXT("ShowConsoleInfo"));//设置新的控制台标题
// 获取屏幕缓冲信息
memset(&conScrBufIn, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO));//初始化
if (GetConsoleScreenBufferInfo(stdOutHandle, &conScrBufIn))
{
wcout << TEXT("屏幕缓冲大小:列数x行数") << conScrBufIn.dwSize.X
<< TEXT("x") << conScrBufIn.dwSize.Y << endl;
wcout << TEXT("控制台光标位置(x,y):(") << conScrBufIn.dwCursorPosition.X
<< TEXT(",") << conScrBufIn.dwCursorPosition.Y << TEXT(")") << endl;
wcout << TEXT("屏幕缓冲字符属性: ") << conScrBufIn.wAttributes << endl;
wcout << TEXT("屏幕缓冲显示窗口位置:") << endl
<< TEXT(" left:") << conScrBufIn.srWindow.Left << endl
<< TEXT(" Right:") << conScrBufIn.srWindow.Right << endl
<< TEXT(" Top:") << conScrBufIn.srWindow.Top << endl
<< TEXT(" Bottom:") << conScrBufIn.srWindow.Bottom << endl;
wcout << TEXT("最大显示窗口大小:") << conScrBufIn.dwMaximumWindowSize.X
<< TEXT("x") << conScrBufIn.dwMaximumWindowSize.Y << endl;
}
// 红色前景色,绿色背景色
SetConsoleTextAttribute(stdOutHandle, FOREGROUND_RED | BACKGROUND_GREEN);//颜色设置
wcout << TEXT("设置红色前景色,绿色背景色") << endl;
wcout << TEXT("测试字符串,ABCabc123*&@!") << endl << endl;
CONSOLE_CURSOR_INFO cursor_info;
memset(&cursor_info, 0, sizeof(cursor_info));
if (GetConsoleCursorInfo(stdOutHandle, &cursor_info))
{
wcout << TEXT("光标可见:") << (cursor_info.bVisible ? TEXT("是") : TEXT("否")) << endl;
wcout << TEXT("光标占位比例 :") << cursor_info.dwSize << TEXT("%") << endl;
cursor_info.bVisible = TRUE;
cursor_info.dwSize = 100;
SetConsoleCursorInfo(stdOutHandle, &cursor_info);
wcout << TEXT("设置100%光标占比(回车继续)") << endl;
getchar();
// 获取光标位置使用GetConsoleScreenBufferInfo函数
COORD cursor_pos = { 0, 15 };
SetConsoleCursorPosition(stdOutHandle, cursor_pos);//这里是移动了光标到指定位置
cursor_info.dwSize = 50;
SetConsoleCursorInfo(stdOutHandle, &cursor_info);
wcout << TEXT("设置50%光标占比 (回车继续)") << endl;
}
getchar();
/*
gotoxy函数实现:
void gotoxy(int x,int y){
COORD pos;
pos.X = x - 1;
pos.Y = y - 1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
*/
// 下面设置需要将控制台屏幕缓冲窗口下移一行,用于移除关于设置控制台标题提示
SMALL_RECT sRect;
sRect.Left = 0;
sRect.Right = 0;
sRect.Top = 1;
sRect.Bottom = 1;
if (!SetConsoleWindowInfo(stdOutHandle, FALSE, &sRect))//设置控制台位置及大小。
{
wcout << "调用SetConsoleWindowInfo失败,错误码" << GetLastError() << endl;
return 0;
}
{
COORD pos;
pos.X = pos.Y = 0;
// 向窗口中填充字符以获得清屏的效果
FillConsoleOutputCharacter(stdOutHandle, ' ', conScrBufIn.dwSize.X * conScrBufIn.dwSize.Y, pos, NULL);
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//将光标移动到起始处
}
getchar();
ReadConsoleInput(stdInHandle, &inRec, 1, &numRead); /* 读取1个输入事件 *///这是一个非阻塞的函数
// 关闭标准输出设备句柄
CloseHandle(stdOutHandle);
// 关闭标准输入设备句柄
CloseHandle(stdInHandle);
return 0;
}