break;
// 按ESC键退出循环
if (keyRec.Event.KeyEvent.bKeyDown) {
ch = keyRec.Event.KeyEvent.uChar.AsciiChar; CharWindow(ch, rc); } } }
pos.X = 0; pos.Y = 0;
SetConsoleCursorPosition(hOut, pos); // 设置光标位置 CloseHandle(hOut); // 关闭标准输出设备句柄 CloseHandle(hIn); // 关闭标准输入设备句柄 }
void CharWindow(char ch, SMALL_RECT rc) // 将ch输入到指定的窗口中 {
static COORD chPos = {rc.Left+1, rc.Top+1};
SetConsoleCursorPosition(hOut, chPos); // 设置光标位置 if ((ch<0x20)||(ch>0x7e)) return;
WriteConsoleOutputCharacter(hOut, &ch, 1, chPos, NULL); if (chPos.X>=(rc.Right-1)) {
chPos.X = rc.Left; chPos.Y++; }
if (chPos.Y>(rc.Bottom-1)) {
DeleteTopLine(rc);
chPos.Y = rc.Bottom-1; }
chPos.X++;
SetConsoleCursorPosition(hOut, chPos); // 设置光标位置 }
void ControlStatus(DWORD state) // 在最后一行显示控制键的状态 {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, bInfo.dwSize.Y-1}; WORD att0 = BACKGROUND_INTENSITY ;
WORD att1 = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_RED;
FillConsoleOutputAttribute(hOut, att0, bInfo.dwSize.X, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X, home, NULL);
SetConsoleTextAttribute(hOut, att1);
COORD staPos = {bInfo.dwSize.X-16,bInfo.dwSize.Y-1}; SetConsoleCursorPosition(hOut, staPos); if (state & NUMLOCK_ON)
WriteConsole(hOut, \ staPos.X += 4;
SetConsoleCursorPosition(hOut, staPos); if (state & CAPSLOCK_ON)
WriteConsole(hOut, \ staPos.X += 5;
SetConsoleCursorPosition(hOut, staPos); if (state & SCROLLLOCK_ON)
WriteConsole(hOut, \
SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢复原来的属性
SetConsoleCursorPosition(hOut, bInfo.dwCursorPosition); // 恢复原来的光标位置 }
void DeleteTopLine(SMALL_RECT rc) {
COORD crDest;
CHAR_INFO chFill;
SMALL_RECT rcClip = rc;
rcClip.Left++; rcClip.Right--; rcClip.Top++; rcClip.Bottom--; crDest.X = rcClip.Left; crDest.Y = rcClip.Top - 1;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); chFill.Attributes = bInfo.wAttributes; chFill.Char.AsciiChar = ' ';
ScrollConsoleScreenBuffer(hOut, &rcClip, &rcClip, crDest, &chFill); }
程序运行结果如下图所示:
十、读取鼠标信息
与读取键盘信息方法相似,鼠标信息也是通过ReadConsoleInput来获取的,其MOUSE_EVENT_RECORD具有下列定义: typedef struct _MOUSE_EVENT_RECORD { COORD dwMousePosition; // 当前鼠标位置 DWORD dwButtonState; // 鼠标按钮状态 DWORD dwControlKeyState; // 键盘控制键状态 DWORD dwEventFlags; // 事件状态 } MOUSE_EVENT_RECORD; 其中,dwButtonState反映了用户按下鼠标按钮的情况,它可以是:FROM_LEFT_1ST_BUTTON_PRESSED(最左边按钮)、RIGHTMOST_BUTTON_PRESSED(最右边按钮)、FROM_LEFT_2ND_BUTTON_PRESSED(左起第二个按钮)、FROM_LEFT_3RD_BUTTON_PRESSED(左起第三个按钮)和
FROM_LEFT_4TH_BUTTON_PRESSED (左起第四个按钮)。而dwEventFlags表示鼠标的事件,如DOUBLE_CLICK(双击)、MOUSE_MOVED(移动)和MOUSE_WHEELED(滚轮滚动,只适用于Windows 2000/XP)。dwControlKeyState的含义同前。 下面举一个例子。这个例子能把鼠标的当前位置显示在控制台窗口的最后一行上,若单击鼠标左键,则在当前位置处写一个字符‘A’,若双击鼠标任一按钮,则程序终止。具体代码如下: #include <WINDOWS.H> #include <STDIO.H> #include <STRING.H> HANDLE hOut; HANDLE hIn; void ClearScreen(void); void DispMousePos(COORD pos); // 在最后一行显示鼠标位置 void main() { hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄 hIn = GetStdHandle(STD_INPUT_HANDLE); // 获取标准输入设备句柄
WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY |
BACKGROUND_BLUE ; // 背景是蓝色,文本颜色是黄色
SetConsoleTextAttribute(hOut, att); ClearScreen(); // 清屏 INPUT_RECORD mouseRec; DWORD state = 0, res; COORD pos = {0, 0}; for(;;) // 循环 {
ReadConsoleInput(hIn, &mouseRec, 1, &res); if (mouseRec.EventType == MOUSE_EVENT){
if (mouseRec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) break;
// 双击鼠标退出循环
pos = mouseRec.Event.MouseEvent.dwMousePosition; DispMousePos(pos);
if (mouseRec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
FillConsoleOutputCharacter(hOut, 'A', 1, pos, NULL); } }
pos.X = 0; pos.Y = 0;
SetConsoleCursorPosition(hOut, pos); // 设置光标位置 CloseHandle(hOut); // 关闭标准输出设备句柄 CloseHandle(hIn); // 关闭标准输入设备句柄 }
void DispMousePos(COORD pos) // 在最后一行显示鼠标位置 {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, bInfo.dwSize.Y-1}; WORD att0 = BACKGROUND_INTENSITY ;
FillConsoleOutputAttribute(hOut, att0, bInfo.dwSize.X, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X, home, NULL);
char s[20];
sprintf(s,\
SetConsoleTextAttribute(hOut, att0); SetConsoleCursorPosition(hOut, home);
WriteConsole(hOut, s, strlen(s), NULL, NULL);
SetConsoleTextAttribute(hOut, bInfo.wAttributes); // 恢复原来的属性
SetConsoleCursorPosition(hOut, bInfo.dwCursorPosition); // 恢复原来的光标位置 }
void ClearScreen(void) {
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo ); COORD home = {0, 0};
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y; FillConsoleOutputAttribute(hOut, bInfo.wAttributes, size, home, NULL);
FillConsoleOutputCharacter(hOut, ' ', size, home, NULL); }
程序运行结果如下:
十一、结语
综上所述,利用控制台窗口的Widows API函数可以设计简洁美观的文本界面,使得用Visual C++ 6.0开发环境深入学习C