好友
阅读权限25
听众
最后登录1970-1-1
|
Jorge
发表于 2019-3-12 12:32
本帖最后由 Jorge 于 2019-3-16 18:57 编辑
(一)概述
操作所谓控制台应用程序,就是指那些需要与传统DOS操作系统保持某种程序的兼容,同时又不需要为用户提供完善界面的程序。简单地讲,就是指在Windows环境下运行的DOS程序。一旦控制台应用程序在Windows操作系统中运行后,就会弹出一个窗口。例如下列代码:[C] 纯文本查看 复制代码 1 2 3 4 5 6 | #include <stdio.h>
int main( int argc, char *argv[])
{
printf ( "Hello, Console!\n" );
return 0;
}
|
单击小型编译工具栏中的“Build”按钮或按F7键,系统出现一个对话框,询问是否将此项目的工作文件夹设定源文件所在的文件夹,单击[是]按钮,系统开始编译。 单击小型编译工具栏中的“Execute Program”按钮或按Ctrl+F5键,运行刚才的程序。 程序运行后,弹出下图的窗口:file:///C:/Users/admini/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg这就是控制台窗口,与传统的DOS屏幕窗口相比最主要的区别有:(1) 默认的控制台窗口有系统菜单和标题,它是一个内存缓冲区窗口,缓冲区大小取决于Windows操作系统的分配;而DOS屏幕是一种物理窗口,不具有Windows窗口特性,其大小取决于ROM BIOS分配的内存空间。(2) 控制台窗口的文本操作是调用低层的Win32 APIs,而DOS屏幕的文本操作是通过调用BIOS的16(10h)中断而实现的。(3) 默认的控制台窗口可以接收键盘和鼠标的输入信息,设备驱动由Windows管理,而DOS屏幕窗口接收鼠标时需要调用33h中断,且鼠标设备驱动程序由自己安装。
(二) 控制台文本窗口的一般控制步骤
在Visual C++ 6.0中,控制台窗口界面的一般编程控制步骤如下:调用GetStdHandle获取当前的标准输入(STDIN)和标准输出(STDOUT)设备句柄。函数原型为:HANDLE GetStdHandle( DWORD nStdHandle );其中,nStdHandle可以是STD_INPUT_HANDLE(标准输入设备句柄)、STD_OUTPUT_HANDLE(标准输出设备句柄)和 STD_ERROR_HANDLE(标准错误句柄)。需要说明的是,“句柄”是Windows最常用的概念。它通常用来标识Windows资源(如菜单、 图标、窗口等)和设备等对象。虽然可以把句柄理解为是一个指针变量类型,但它不是对象所在的地址指针,而是作为Windows系统内部表的索引值来使用 的。调用相关文本界面控制的API函数。这些函数可分为三类。一是用于控制台窗口操作的函数(包括窗口的缓冲区大小、窗口前景字符和背景颜色、窗口标题、大小和位置等);二是用于控制台输入输出的函数(包括字符属性操作函数);其他的函数并为最后一类。 调用CloseHandle()来关闭输入输出句柄。 注意,在程序中还必须包含头文件windows.h。下面看一个程序:[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <windows.h>#include <stdio.h>
#include <conio.h>
int main( void )
{
HANDLE hOut;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
COORD pos = {0, 0};
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &bInfo );
printf ( "\n\nThe soul selects her own society\n" );
printf ( "Then shuts the door\n" );
printf ( "On her devine majority\n" );
printf ( "Obtrude no more\n\n" );
_getch();
FillConsoleOutputCharacter(hOut, ' ' , bInfo.dwSize.X * bInfo.dwSize.Y, pos, NULL);
CloseHandle(hOut);
return 0;
}
程序中,COORD和CONSOLE_SCREEN_BUFFER_ INFO是wincon.h定义的控制台结构体类型,其原型如下:
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD;
typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
} CONSOLE_SCREEN_BUFFER_INFO ;
|
还需要说明的是,虽然在C++中,iostream.h定义了cin和cout的标准输入和输出流对象。但它们只能实现基本的输入输出操作,对于控制台窗口界面的控制却无能为力,而且不能与stdio.h和conio.h友好相处,因为iostream.h和它们是C++两套不同的输入 输出操作方式,使用时要特别注意。
(三)控制台窗口操作 操作用于控制台窗口操作的API函数如下:GetConsoleScreenBufferInfo 获取控制台窗口信息GetConsoleTitle 获取控制台窗口标题ScrollConsoleScreenBuffer 在缓冲区中移动数据块SetConsoleScreenBufferSize 更改指定缓冲区大小SetConsoleTitle 设置控制台窗口标题SetConsoleWindowInfo 设置控制台窗口信息此外,还有窗口字体、显示模式等控制函数,这里不再细说。下列举一个示例,程序如下:[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <windows.h>#include <stdio.h>
#include <conio.h>
int main( void )
{
char strTitle[255];
CONSOLE_SCREEN_BUFFER_INFO bInfo;
COORD size = {80, 25};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &bInfo );
GetConsoleTitle(strTitle, 255);
printf ( "当前窗口标题是:\n%s\n" , strTitle);
_getch();
SetConsoleTitle( "控制台窗口操作" );
GetConsoleTitle(strTitle, 255);
printf ( "当前窗口标题是:\n%s\n" , strTitle);
_getch();
SetConsoleScreenBufferSize(hOut,size);
_getch();
SMALL_RECT rc = {0,0, 80-1, 25-1};
SetConsoleWindowInfo(hOut, true ,&rc);
CloseHandle(hOut);
return 0;
}
|
需要说明的是,控制台窗口的原点坐标是(0, 0),而最大的坐标是缓冲区大小减1,例如当缓冲区大小为80*25时,其最大的坐标是(79, 24)。
(四)文本属性操作 操作与DOS字符相似,控制台窗口中的字符也有相应的属性。这些属性分为:文本的前景色、背景色和双字节字符集(DBCS)属性三种。事实上,我们最关心是文本颜色,这样可以构造出美观的界面。颜色属性都是一些预定义标识:FOREGROUND_BLUE 蓝色FOREGROUND_GREEN 绿色 FOREGROUND_RED 红色FOREGROUND_INTENSITY 加强BACKGROUND_BLUE 蓝色背景BACKGROUND_GREEN 绿色背景BACKGROUND_RED 红色背景BACKGROUND_INTENSITY 背景色加强COMMON_LVB_REVERSE_VIDEO 反色与文本属性相关的主要函数有:BOOL FillConsoleOutputAttribute( // 填充字符属性HANDLE hConsoleOutput, // 句柄WORD wAttribute, // 文本属性DWORD nLength, // 个数COORD dwWriteCoord, // 开始位置LPDWORD lpNumberOfAttrsWritten // 返回填充的个数);BOOL SetConsoleTextAttribute( // 设置WriteConsole等函数的字符属性HANDLE hConsoleOutput, // 句柄WORD wAttributes // 文本属性);BOOL WriteConsoleOutputAttribute( // 在指定位置处写属性HANDLE hConsoleOutput, // 句柄CONST WORD *lpAttribute, // 属性DWORD nLength, // 个数COORD dwWriteCoord, // 起始位置LPDWORD lpNumberOfAttrsWritten // 已写个数);另外,获取当前控制台窗口的文本属性是通过调用函数GetConsoleScreenBufferInfo后,在CONSOLE_SCREEN_ BUFFER_INFO结构成员wAttributes中得到。
(五)文本输出操作 文本输出函数有:BOOL FillConsoleOutputCharacter( // 填充指定数据的字符HANDLE hConsoleOutput, // 句柄TCHAR cCharacter, // 字符DWORD nLength, // 字符个数COORD dwWriteCoord, // 起始位置LPDWORD lpNumberOfCharsWritten // 已写个数);BOOL WriteConsole( // 在当前光标位置处插入指定数量的字符HANDLE hConsoleOutput, // 句柄CONST VOID *lpBuffer, // 字符串DWORD nNumberOfCharsToWrite, // 字符个数LPDWORD lpNumberOfCharsWritten, // 已写个数LPVOID lpReserved // 保留);BOOL WriteConsoleOutput( // 向指定区域写带属性的字符HANDLE hConsoleOutput, // 句柄CONST CHAR_INFO *lpBuffer, // 字符数据区COORD dwBufferSize, // 数据区大小COORD dwBufferCoord, // 起始坐标PSMALL_RECT lpWriteRegion // 要写的区域);BOOL WriteConsoleOutputCharacter( // 在指定位置处插入指定数量的字符HANDLE hConsoleOutput, // 句柄LPCTSTR lpCharacter, // 字符串DWORD nLength, // 字符个数COORD dwWriteCoord, // 起始位置LPDWORD lpNumberOfCharsWritten // 已写个数);可以看出:WriteConsoleOutput函数功能相当于SetConsoleTextAttribute和WriteConsole 的功能。而WriteConsoleOutputCharacter函数相当于SetConsoleCursorPosition(设置光标位置)和 WriteConsole的功能。不过在具体使用要注意它们的区别。
(六)文本操作示例 下面看一个示例程序: [C] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | HANDLE hOut;
void ShadowWindowLine( char *str);
void DrawBox( bool bSingle, SMALL_RECT rc);
int main( void )
{
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleOutputCP(437);
ShadowWindowLine( "Display a line of words, and center the window with shadow." );
CloseHandle(hOut);
return 0;
}
void ShadowWindowLine( char *str)
{
SMALL_RECT rc;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
WORD att0,att1,attText;
int i, chNum = strlen (str);
GetConsoleScreenBufferInfo( hOut, &bInfo );
rc.Left = (bInfo.dwSize.X - chNum)/2 - 2;
rc.Top = 8;
rc.Right = rc.Left + chNum + 4;
rc.Bottom = rc.Top + 4;
att0 = BACKGROUND_INTENSITY;
att1 = FOREGROUND_RED |FOREGROUND_GREEN |FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_RED | BACKGROUND_BLUE;
attText = FOREGROUND_RED |FOREGROUND_INTENSITY;
COORD posShadow = {rc.Left+1, rc.Top+1}, posText = {rc.Left, rc.Top};
for (i=0; i<5; i++)
{
FillConsoleOutputAttribute(hOut, att0, chNum + 4, posShadow, NULL);
posShadow.Y++;
}
for (i=0;i<5;i++)
{
FillConsoleOutputAttribute(hOut, att1,chNum + 4, posText, NULL);
posText.Y++;
}
posText.X = rc.Left + 2;
posText.Y = rc.Top + 2;
WriteConsoleOutputCharacter(hOut, str, strlen (str), posText, NULL);
DrawBox( true , rc);
SetConsoleTextAttribute(hOut, bInfo.wAttributes);
}
void DrawBox( bool bSingle, SMALL_RECT rc)
{
char chBox[6];
COORD pos;
if (bSingle)
{
chBox[0] = ( char )0xda;
chBox[1] = ( char )0xbf;
chBox[2] = ( char )0xc0;
chBox[3] = ( char )0xd9;
chBox[4] = ( char )0xc4;
chBox[5] = ( char )0xb3;
}
else
{
chBox[0] = ( char )0xc9;
chBox[1] = ( char )0xbb;
chBox[2] = ( char )0xc8;
chBox[3] = ( char )0xbc;
chBox[4] = ( char )0xcd;
chBox[5] = ( char )0xba;
}
for (pos.X = rc.Left+1;pos.X<rc.Right-1;pos.X++)
{
pos.Y = rc.Top;
WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
if (pos.X == rc.Left+1)
{
pos.X--;
WriteConsoleOutputCharacter(hOut, &chBox[0],1, pos, NULL);
pos.X++;
}
if (pos.X == rc.Right-2)
{
pos.X++;
WriteConsoleOutputCharacter(hOut, &chBox[1], 1, pos, NULL);
pos.X--;
}
pos.Y = rc.Bottom;
WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
if (pos.X == rc.Left+1)
{
pos.X--;
WriteConsoleOutputCharacter(hOut, &chBox[2], 1, pos, NULL);
pos.X++;
}
if (pos.X==rc.Right-2)
{
pos.X++;
WriteConsoleOutputCharacter(hOut, &chBox[3], 1, pos, NULL);
pos.X--;
}
}
for (pos.Y = rc.Top+1; pos.Y<=rc.Bottom-1; pos.Y++)
{
pos.X = rc.Left;
WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
pos.X = rc.Right-1;
WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
}
}
|
程序运行结果如下图所示:file:///C:/Users/admini/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg需要说明的是:①在上述例子中,如果调用DrawBox函数时,传递的第一个参数不是true而是false,那么画出来的边框将是双线的。运行结果如下:file:///C:/Users/admini/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg②如果在上述程序无法编译通过,您可以这样修改,即程序中调用WriteConsoleOutputCharacter和FillConsoleOutputAttribute函数的时候,最后一个参数不用NULL,而是先定义一个变量:DWORD written;然后把 &written作为最后一个参数。③上述程序在不同的字符代码页面(code page)下显示的结果是不同的。例如,中文Windows操作系统的默认代码页是简体中文(936),在该代码页面下值超过128的单字符在Windows NT/XP是显示不出来的。
(七)滚动和移动操作 ScrollConsoleScreenBuffer是实现文本区滚动和移动的API函数。它可以将指定的一块文本区域移动到另一个区域,被移空的那块区域由指定字符填充。函数的原型如下:BOOL ScrollConsoleScreenBuffer(HANDLE hConsoleOutput, // 句柄CONST SMALL_RECT* lpScrollRectangle, // 要滚动或移动的区域CONST SMALL_RECT* lpClipRectangle, // 裁剪区域COORD dwDestinationOrigin, // 新的位置CONST CHAR_INFO* lpFill // 填充字符);利用这个API函数还可以实现删除指定行的操作。下面来举一个例子,程序如下:[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <windows.h>#include <stdio.h>
#include <conio.h>
HANDLE hOut;
void DeleteLine( int row);
void MoveText( int x, int y, SMALL_RECT rc);
void ClearScreen( void );
int main( void )
{
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
WORD att = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE;
SetConsoleTextAttribute(hOut, att);
ClearScreen();
printf ( "\n\nThe soul selects her own society\n" );
printf ( "Then shuts the door;\n" );
printf ( "On her devine majority;\n" );
printf ( "Obtrude no more.\n\n" );
COORD endPos = {0, 15};
SetConsoleCursorPosition(hOut, endPos);
SMALL_RECT rc = {0, 2, 40, 5};
_getch();
MoveText(10, 5, rc);
_getch();
DeleteLine(5);
CloseHandle(hOut);
return 0;
}
void DeleteLine( int row)
{
SMALL_RECT rcScroll, rcClip;
COORD crDest = {0, row - 1};
CHAR_INFO chFill;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo );
rcScroll.Left = 0;
rcScroll.Top = row;
rcScroll.Right = bInfo.dwSize.X - 1;
rcScroll.Bottom = bInfo.dwSize.Y - 1;
rcClip = rcScroll;
chFill.Attributes = bInfo.wAttributes;
chFill.Char.AsciiChar = ' ' ;
ScrollConsoleScreenBuffer(hOut, &rcScroll, &rcClip, crDest, &chFill);
}
void MoveText( int x, int y, SMALL_RECT rc)
{
COORD crDest = {x, y};
CHAR_INFO chFill;
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo );
chFill.Attributes = bInfo.wAttributes;
chFill.Char.AsciiChar = ' ' ;
ScrollConsoleScreenBuffer(hOut, &rc, NULL, crDest, &chFill);
}
void ClearScreen( void )
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo );
COORD home = {0, 0};
WORD att = bInfo.wAttributes;
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y;
FillConsoleOutputAttribute(hOut, att, size, home, NULL);
FillConsoleOutputCharacter(hOut, ' ' , size, home, NULL);
}
|
程序中,实现删除行的操作DeleteLine的基本原理是:首先将裁剪区域和移动区域都设置成指定行row(包括该行)以下的控制台窗口区域,然后将移动的位置指定为(0, row-1)。这样,超出裁剪区域的内容被裁剪掉,从而达到删除行的目的。需要说明的是,若裁剪区域参数为NULL,则裁剪区域为整个控制台窗口。
(八)光标操作操作 控制台窗口中的光标反映了文本插入的当前位置,通过SetConsoleCursorPosition函数可以改变这个“当前”位置,这样就能控制字符(串)输出。事实上,光标本身的大小和显示或隐藏也可以通过相应的API函数进行设定。例如:BOOL SetConsoleCursorInfo( // 设置光标信息HANDLE hConsoleOutput, // 句柄CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo // 光标信息);BOOL GetConsoleCursorInfo( // 获取光标信息HANDLE hConsoleOutput, // 句柄PCONSOLE_CURSOR_INFO lpConsoleCursorInfo // 返回光标信息);这两个函数都与CONSOLE_CURSOR_INFO结构体类型有关,其定义如下:typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; // 光标百分比大小 BOOL bVisible; // 是否可见} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;需要说明的是,dwSize值反映了光标的大小,它的值范围为1-100;当为1时,光标最小,仅是一条最靠下的水平细线,当为100,光标最大,为一个字符大小的方块。
(九)读取键盘信息操作 键盘事件通常有字符事件和按键事件,这些事件所附带的信息构成了键盘信息。它是通过API函数ReadConsoleInput来获取的,其原型如下:BOOL ReadConsoleInput(HANDLE hConsoleInput, // 输入设备句柄PINPUT_RECORD lpBuffer, // 返回数据记录DWORD nLength, // 要读取的记录数LPDWORD lpNumberOfEventsRead // 返回已读取的记录数);其中,INPUT_RECORD定义如下: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;与键盘事件相关的记录结构KEY_EVENT_RECORD定义如下:typedef struct _KEY_EVENT_RECORD { BOOL bKeyDown; // TRUE表示键按下,FALSE表示键释放WORD wRepeatCount; // 按键次数WORD wVirtualKeyCode; // 虚拟键代码WORD wVirtualScanCode; // 虚拟键扫描码union { WCHAR UnicodeChar; // 宽字符CHAR AsciiChar; // ASCII字符} uChar; // 字符DWORD dwControlKeyState; // 控制键状态} KEY_EVENT_RECORD;我们知道,键盘上每一个有意义的键都对应着一个唯一的扫描码,虽然扫描码可以作为键的标识,但它依赖于具体设备的。因此,在应用程序中,使用的往往是与具体设备无关的虚拟键代码。这种虚拟键代码是与设备无关的键盘编码。在Visual C++中,最常用的虚拟键代码已被定义在Winuser.h中,例如:VK_SHIFT表示SHIFT键,VK_F1表示功能键F1等。上述结构定义中,dwControlKeyState用来表示控制键状态,它可以是CAPSLOCK_ON(CAPS LOCK灯亮)、ENHANCED_KEY(按下扩展键)、LEFT_ALT_PRESSED(按下左ALT键)、LEFT_CTRL_PRESSED(按下左CTRL键)、NUMLOCK_ON (NUM LOCK灯亮)、RIGHT_ALT_PRESSED(按下右ALT键)、RIGHT_CTRL_PRESSED(按下右CTRL键)、SCROLLLOCK_ON(SCROLL LOCK灯亮)和SHIFT_PRESSED(按下SHIFT键)中的一个或多个值的组合。下面的程序是将用户按键的字符输入到一个控制台窗口的某个区域中,并当按下NUM LOCK、CAPS LOCK和SCROLLLOCK键时,在控制台窗口的最后一行显示这些键的状态。[C] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | #include <windows.h>HANDLE hOut;
HANDLE hIn;
void DrawBox( bool bSingle, SMALL_RECT rc);
void ClearScreen( void );
void CharWindow( char ch, SMALL_RECT rc);
void ControlStatus( DWORD state);
void DeleteTopLine(SMALL_RECT rc);
int main( void )
{
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 keyRec;
DWORD state = 0, res;
char ch;
SMALL_RECT rc = {20, 2, 40, 12};
DrawBox( false , rc);
COORD pos = {rc.Left+1, rc.Top+1};
SetConsoleCursorPosition(hOut, pos);
for (;;)
{
ReadConsoleInput(hIn, &keyRec, 1, &res);
if (state != keyRec.Event.KeyEvent.dwControlKeyState)
{
state = keyRec.Event.KeyEvent.dwControlKeyState;
ControlStatus(state);
}
if (keyRec.EventType == KEY_EVENT)
{
if (keyRec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
break ;
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);
return 0;
}
void CharWindow( char ch, SMALL_RECT rc)
{
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-2))
{
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, 24};
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,24};
SetConsoleCursorPosition(hOut, staPos);
if (state & NUMLOCK_ON)
WriteConsole(hOut, "NUM" , 3, NULL, NULL);
staPos.X += 4;
SetConsoleCursorPosition(hOut, staPos);
if (state & CAPSLOCK_ON)
WriteConsole(hOut, "CAPS" , 4, NULL, NULL);
staPos.X += 5;
SetConsoleCursorPosition(hOut, staPos);
if (state & SCROLLLOCK_ON)
WriteConsole(hOut, "SCROLL" , 6, NULL, NULL);
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 -= 2;
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);
}
void ClearScreen( void )
{
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo( hOut, &bInfo );
COORD home = {0, 0};
WORD att = bInfo.wAttributes;
unsigned long size = bInfo.dwSize.X * bInfo.dwSize.Y;
FillConsoleOutputAttribute(hOut, att, size, home, NULL);
FillConsoleOutputCharacter(hOut, ' ' , size, home, NULL);
}
void DrawBox( bool bSingle, SMALL_RECT rc)
{
char chBox[6];
COORD pos;
if (bSingle)
{
chBox[0] = ( char )0xda;
chBox[1] = ( char )0xbf;
chBox[2] = ( char )0xc0;
chBox[3] = ( char )0xd9;
chBox[4] = ( char )0xc4;
chBox[5] = ( char )0xb3;
}
else
{
chBox[0] = ( char )0xc9;
chBox[1] = ( char )0xbb;
chBox[2] = ( char )0xc8;
chBox[3] = ( char )0xbc;
chBox[4] = ( char )0xcd;
chBox[5] = ( char )0xba;
}
for (pos.X = rc.Left+1;pos.X<rc.Right-1;pos.X++)
{
pos.Y = rc.Top;
WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
if (pos.X == rc.Left+1)
{
pos.X--;
WriteConsoleOutputCharacter(hOut, &chBox[0],1, pos, NULL);
pos.X++;
}
if (pos.X == rc.Right-2)
{
pos.X++;
WriteConsoleOutputCharacter(hOut, &chBox[1], 1, pos, NULL);
pos.X--;
}
pos.Y = rc.Bottom;
WriteConsoleOutputCharacter(hOut, &chBox[4], 1, pos, NULL);
if (pos.X == rc.Left+1)
{
pos.X--;
WriteConsoleOutputCharacter(hOut, &chBox[2], 1, pos, NULL);
pos.X++;
}
if (pos.X==rc.Right-2)
{
pos.X++;
WriteConsoleOutputCharacter(hOut, &chBox[3], 1, pos, NULL);
pos.X--;
}
}
for (pos.Y = rc.Top+1; pos.Y<=rc.Bottom-1; pos.Y++)
{
pos.X = rc.Left;
WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
pos.X = rc.Right-1;
WriteConsoleOutputCharacter(hOut, &chBox[5], 1, pos, NULL);
}
}
|
(十)读取鼠标信息操作 与读取键盘信息方法相似,鼠标信息也是通过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’,若双击鼠标任一按钮,则程序终止。具体代码如下:[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #include <windows.h>#include <stdio.h>
#include <string.h>
HANDLE hOut;
HANDLE hIn;
void ClearScreen( void );
void DispMousePos(COORD pos);
int 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 = 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, 24};
WORD att0 = BACKGROUND_INTENSITY ;
FillConsoleOutputAttribute(hOut, att0, bInfo.dwSize.X, home, NULL);
FillConsoleOutputCharacter(hOut, ' ' , bInfo.dwSize.X, home, NULL);
char s[20];
sprintf (s, "X = %2lu, Y = %2lu" ,pos.X, pos.Y);
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);
}
|
|
免费评分
-
查看全部评分
|