一:设置句柄与窗口信息
在Windows操作系统下用C语言编写控制台的窗口界面首先要获取当前标准输入和标准输出设备的句柄。通过调用函数GetStdHandle可以获取当前标准输入以及输出设备的句柄。函数原型为:
- HANDLE GetStdHandle(DWORD nStdHandle);
-
-
-
-
-
-
需要说明的是,“句柄”是Windows最常用的一个概念。它通常用来标识Windows资源(如菜单、 图标、窗口等)和设备等对象。虽然可以把句柄理解为是一个指针变量类型,但它不是对象所在的地址指针,而是作为Windows系统内部表的索引值来使用 的。调用相关文本界面控制的API函数。这些函数可分为三类。一是用于控制台窗口操作的函数(包括窗口的缓冲区大小、窗口前景字符和背景颜色、窗口标题、大小和位置等);二是用于控制台输入输出的函数(包括字符属性操作函数);其他的函数并为最后一类。通过调用CloseHandle函数来关闭输入输出句柄。
示例程序:
- #include
- #include
- #include
-
- int main(int argc,char *argv[])
- {
- HANDLE handle_out;
- CONSOLE_SCREEN_BUFFER_INFO screen_info;
- COORD pos = {0, 0};
- handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- GetConsoleScreenBufferInfo(handle_out, &screen_info);
- _getch();
-
-
-
-
-
-
- FillConsoleOutputCharacter(handle_out, 'A', screen_info.dwSize.X * screen_info.dwSize.Y, pos, NULL);
- CloseHandle(handle_out);
- return 0;
- }
-
-
-
-
- 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();
-
-
- SetConsoleScreenBufferSize();
-
-
- SetConsoleTitle();
-
-
- SetConsoleWindowInfo();
下面的示例程序用于说明此类函数的使用:
- #include
- #include
- #include
- #include
- #define N 255
-
- int main()
- {
- HANDLE handle_out;
- CONSOLE_SCREEN_BUFFER_INFO scbi;
- COORD size = {80, 25};
- char strtitle[N];
- handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- GetConsoleScreenBufferInfo(handle_out, &scbi);
- GetConsoleTitle(strtitle, N);
- printf("当前窗口标题为:%s\n", strtitle);
- _getch();
- SetConsoleTitle("控制台窗口操作");
- GetConsoleTitle(strtitle, N);
- printf("当前窗口标题为:%s\n", strtitle);
- _getch();
- SetConsoleScreenBufferSize(handle_out, size);
- _getch();
- SMALL_RECT rc = {0, 0, 80-1, 25-1};
- SetConsoleWindowInfo(handle_out, 1, &rc);
- CloseHandle(handle_out);
- return 0;
- }
其中,SetConsoleScreenBufferSize函数指定新的控制台屏幕缓冲区的大小,以字符列和行为单位。指定的宽度和高度不能小于控制台屏幕缓冲区窗口的宽度和高度。指定的大小也不能小于系统允许的最小大小。这个最低取决于控制台当前的字体大小 (由用户选定)。
三:文本属性
在这里介绍一个设置文本属性的函数,原型如下
- BOOL SetConsoleTextAttribute(
- HANDLE hConsoleOutput,
- WORD wAttributes
- );
顺便提一下文本属性,其实就是颜色属性,有背景色和前景色(就是字符的颜色)两类,每一类只提供三原色(红,绿,蓝)和加强色(灰色,可与其他颜色搭配使用,使颜色变亮,后面会提到)。最后还有一个反色(不太清楚这个到底怎么用,很奇葩的东西)。示例程序如下:
- #include
- #include
- #include
- #include
-
-
-
-
-
-
-
-
-
-
-
-
-
- const WORD FORE_BLUE = FOREGROUND_BLUE;
- const WORD FORE_GREEN = FOREGROUND_GREEN;
- const WORD FORE_RED = FOREGROUND_RED;
- const WORD FORE_PURPLE = FORE_BLUE | FORE_RED;
- const WORD FORE_CYAN = FORE_BLUE | FORE_GREEN;
- const WORD FORE_YELLOW = FORE_RED | FORE_GREEN;
- const WORD FORE_GRAY = FOREGROUND_INTENSITY;
- const WORD BACK_BLUE = BACKGROUND_BLUE;
- const WORD BACK_GREEN = BACKGROUND_GREEN;
- const WORD BACK_RED = BACKGROUND_RED;
- const WORD BACK_PURPLE = BACK_BLUE | BACK_RED;
- const WORD BACK_CYAN = BACK_BLUE | BACK_GREEN;
- const WORD BACK_YELLOW = BACK_RED | BACK_GREEN;
- const WORD BACK_GRAY = BACKGROUND_INTENSITY;
-
- int main()
- {
- HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- GetConsoleScreenBufferInfo(handle_out, &csbi);
- SetConsoleTextAttribute(handle_out, FORE_BLUE);
- printf("蓝色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_RED);
- printf("红色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_GREEN);
- printf("绿色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_PURPLE);
- printf("紫色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_CYAN);
- printf("青色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_YELLOW);
- printf("黄色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_GRAY);
- printf("灰色字符\n");
- SetConsoleTextAttribute(handle_out, FORE_GREEN | FORE_BLUE | FORE_RED);
- printf("白色字符\n");
- SetConsoleTextAttribute(handle_out, BACK_BLUE);
- printf("蓝色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_RED);
- printf("红色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_GREEN);
- printf("绿色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_PURPLE);
- printf("紫色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_CYAN);
- printf("青色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_YELLOW);
- printf("黄色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_GRAY);
- printf("灰色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_BLUE | BACK_RED | BACK_GREEN);
- printf("白色背景\n");
- SetConsoleTextAttribute(handle_out, BACK_GREEN | FORE_RED);
- printf("绿色背景与红色字符的混合\n");
- SetConsoleTextAttribute(handle_out, FOREGROUND_INTENSITY | FORE_RED);
- printf("亮色的生成,与加强色融合\n");
- return 0;
- }
上述示例程序最好用C++来中编译,因为有C语言的编译器或者IDE不支持上述的定义常量的方式。需要从这个示例中了解的是三原色的混合是用C语言位运算中的按位或 | 运算符,背景颜色与字符颜色的同时定义也是使用这个运算符融合。另外,将任意颜色与对应的加强色(灰色,有前景和背景两种,需要对应)融合后会成为对应颜色的高亮版,比如红色字符与前景加强色的融合会结合成亮红色。
至于反色,大家可以试试,当我设置了文本属性为反色后,输入字符都不显示了,但是下标还在移动,我估计反色将白色字符变成了黑色字符,与黑色背景一样,所以没有显示出来。至于反色与其他的组合以及其他的颜色组合,还需要大家一起探索、、、
四:文本属性
文本颜色属性已经学会了,那么下面就学习几个比较常用的文本输出函数,如下:
- BOOL FillConsoleOutputAttribute(
- HANDLE hConsoleOutput,
- WORD wAttribute,
- DWORD nLength,
- COORD dwWriteCoord,
- LPDWORD lpNumberOfAttrsWritten
- );
- BOOL FillConsoleOutputCharacter(
- HANDLE hConsoleOutput,
- TCHAR cCharacter,
- DWORD nLength,
- COORD dwWriteCoord,
- LPDWORD lpNumberOfCharsWritten
- );
- BOOL WriteConsoleOutputCharacter(
- HANDLE hConsoleOutput,
- LPCTSTR lpCharacter,
- DWORD nLength,
- COORD dwWriteCoord,
- LPDWORD lpNumberOfCharsWritten
- );
另外再介绍一个表示区域的结构体,如下:
- typedef struct _SMALL_RECT
- {
- SHORT Left;
- SHORT Top;
- SHORT Right;
- SHORT Bottom;
- } SMALL_RECT;
-
-
-
-
-
-
-
通过以上的文本输出函数,我们来做一个简单的在一个具有阴影效果的窗口显示字符串的示例程序,如下:
- #include
- #include
- #include
- #include
-
- int main()
- {
- char *str = "Hello World!";
- int len = strlen(str), i;
- WORD shadow = BACKGROUND_INTENSITY;
- WORD text = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
- HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- GetConsoleScreenBufferInfo(handle_out, &csbi);
- SMALL_RECT rc;
- COORD posText;
- COORD posShadow;
-
- rc.Top = 8;
- rc.Bottom = rc.Top + 4;
- rc.Left = (csbi.dwSize.X - len) / 2 - 2;
- rc.Right = rc.Left + len + 4;
-
- posText.X = rc.Left;
- posText.Y = rc.Top;
-
- posShadow.X = posText.X + 1;
- posShadow.Y = posText.Y + 1;
- for (i=0; i<5; ++i)
- {
- FillConsoleOutputAttribute(handle_out, shadow, len + 4, posShadow, NULL);
- posShadow.Y++;
- }
- for (i=0; i<5; ++i)
- {
- FillConsoleOutputAttribute(handle_out, text, len + 4, posText, NULL);
- posText.Y++;
- }
-
- posText.X = rc.Left + 2;
- posText.Y = rc.Top + 2;
- WriteConsoleOutputCharacter(handle_out, str, len, posText, NULL);
- SetConsoleTextAttribute(handle_out, csbi.wAttributes);
- CloseHandle(handle_out);
- return 0;
- }
以上样例在Code::Blocks 13.12中编译通过。
五:文本移动
控制文本的移动是控制台窗口界面编程的一个很重要的功能,有了这个功能我们可以实现界面的滚动。下面我们介绍一个控制文本移动的函数,如下:
- BOOL ScrollConsoleScreenBuffer(
- HANDLE hConsoleOutput,
- const SMALL_RECT *lpScrollRectangle,
- const SMALL_RECT *lpClipRectangle,
- COORD dwDestinationOrigin,
- const CHAR_INFO *lpFill
- );
下面来看一个移动文本的样例程序,如下:
- #include
- #include
- #include
- #include
-
- int main()
- {
- HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- SMALL_RECT scroll;
- COORD pos = {0, 5};
- CHAR_INFO chFill;
- GetConsoleScreenBufferInfo(handle_out, &csbi);
-
- chFill.Char.AsciiChar = ' ';
- chFill.Attributes = csbi.wAttributes;
-
- printf("00000000000000000000000000000\n");
- printf("11111111111111111111111111111\n");
- printf("22222222222222222222222222222\n");
- printf("33333333333333333333333333333\n");
-
- scroll.Left = 1;
- scroll.Top = 1;
- scroll.Right = 10;
- scroll.Bottom = 2;
- ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill);
- return 0;
- }
在上面的样例程序中,裁剪区域是整个控制台窗口的屏幕缓冲区,现在如果我们把裁剪区域设定为与移动区域一样,也就是说ScrollConsoleScreenBuffer函数的第三个参数也改成&scroll,那么结果会怎么样呢?
为什么会发生这种现象呢?很明显示因为裁剪区域的设定问题,现在我们把裁剪区域依旧设定成移动区域,但是我们只把移动区域下移一行而不是移动在别的位置,看看会有什么现象发生?
现在我们应该可以猜想出结论了,别急,再做一个实验,现在我们将裁减区域又重新改为整个屏幕缓冲区,看看会有什么样的现象发生?
再来最后一个实验,我们将裁减区域减小为移动区域的上半部分,继续执行下移一行的操作,看看最终结果会怎么样?
好了,现在我们通过归纳可以得出几个结论了,那就是
一,裁减区域以外的区域不会受文本移动的影响。具体是:
1,裁减区域以外的区域不会被移动过来的区域覆盖,
2,裁减区域以外的区域被移动到他处之后原区域不发生变化,因此不需要填充字符。
总的归纳来说也就是原来是什么样子,文本移动后还是什么样子,不会改变。
二,裁减区域以内的区域受文本移动的影响。具体是:
1,当裁减区域以内的区域被移动到他处造成该区域为空时会被设定的字符填充,
2,裁减区域以内的区域会被移动过来的区域覆盖。
总的归纳来说也就是完全受文本移动的影响,移动过来就被覆盖,被移走就由设定的字符来填充
六:光标操作
控制文本的移动是控制台窗口界面编程的一个很重要的功能,有了这个功能我们可以实现界面的滚动。下面我们介绍一个控制文本移动的函数,如下:
- BOOL ScrollConsoleScreenBuffer(
- HANDLE hConsoleOutput,
- const SMALL_RECT *lpScrollRectangle,
- const SMALL_RECT *lpClipRectangle,
- COORD dwDestinationOrigin,
- const CHAR_INFO *lpFill
- );
下面来看一个移动文本的样例程序,如下:
- #include
- #include
- #include
- #include
-
- int main()
- {
- HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- SMALL_RECT scroll;
- COORD pos = {0, 5};
- CHAR_INFO chFill;
- GetConsoleScreenBufferInfo(handle_out, &csbi);
-
- chFill.Char.AsciiChar = ' ';
- chFill.Attributes = csbi.wAttributes;
-
- printf("00000000000000000000000000000\n");
- printf("11111111111111111111111111111\n");
- printf("22222222222222222222222222222\n");
- printf("33333333333333333333333333333\n");
-
- scroll.Left = 1;
- scroll.Top = 1;
- scroll.Right = 10;
- scroll.Bottom = 2;
- ScrollConsoleScreenBuffer(handle_out, &scroll, NULL, pos, &chFill);
- return 0;
- }
在上面的样例程序中,裁剪区域是整个控制台窗口的屏幕缓冲区,现在如果我们把裁剪区域设定为与移动区域一样,也就是说ScrollConsoleScreenBuffer函数的第三个参数也改成&scroll,那么结果会怎么样呢?
为什么会发生这种现象呢?很明显示因为裁剪区域的设定问题,现在我们把裁剪区域依旧设定成移动区域,但是我们只把移动区域下移一行而不是移动在别的位置,看看会有什么现象发生?
现在我们应该可以猜想出结论了,别急,再做一个实验,现在我们将裁减区域又重新改为整个屏幕缓冲区,看看会有什么样的现象发生?
再来最后一个实验,我们将裁减区域减小为移动区域的上半部分,继续执行下移一行的操作,看看最终结果会怎么样?
好了,现在我们通过归纳可以得出几个结论了,那就是
一,裁减区域以外的区域不会受文本移动的影响。具体是:
1,裁减区域以外的区域不会被移动过来的区域覆盖,
2,裁减区域以外的区域被移动到他处之后原区域不发生变化,因此不需要填充字符。
总的归纳来说也就是原来是什么样子,文本移动后还是什么样子,不会改变。
二,裁减区域以内的区域受文本移动的影响。具体是:
1,当裁减区域以内的区域被移动到他处造成该区域为空时会被设定的字符填充,
2,裁减区域以内的区域会被移动过来的区域覆盖。
总的归纳来说也就是完全受文本移动的影响,移动过来就被覆盖,被移走就由设定的字符来填充
七:键盘事件
输入事件中的键盘事件通常有字符事件和按键事件,这些事件的附带信息构成了键盘输入的信息,而想要读取这些信息,是要通过API函数ReadConsoleInput来获取的,函数原型如下:
- BOOL ReadConsoleInput(
- HANDLE hConsoleInput,
- PINPUT_RECORD lpBuffer,
- DWORD nLength,
- LPDWORD lpNumberOfEventsRead
- );
-
下面介绍几个和读取键盘输入事件有关的结构体,各结构体原型如下:
- 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;
-
-
-
-
-
-
-
-
-
- typedef struct _KEY_EVENT_RECORD
- {
- BOOL bKeyDown;
- WORD wRepeatCount;
- WORD wVirtualKeyCode;
- WORD wVirtualScanCode;
- union
- {
- WCHAR UnicodeChar;
- CHAR AsciiChar;
- } uChar;
- DWORD dwControlKeyState;
- } KEY_EVENT_RECORD;
-
-
-
-
-
-
-
-
-
-
-
-
当输入事件为键盘事件时,事件类型就为键盘事件,为其他事件时,事件类型就为对应的事件。另外,键盘上每个有意义的键都对应着一个唯一的扫描码,虽然扫描码可以作为键的标识,但是它是依赖于具体的设备的。因此,在应用程序中,使用的往往是与具体设备无关的虚拟键代码。这种虚拟键代码是一种与具体设备无关的键盘编码。而控制键状态比如大写锁定开启状态,Ctrl键按下状态等、、、
下面是部分常用虚拟键代码表:
以上是部分常用的微软虚拟键盘码表,想要知道更详细的,请参见MSDN。其中各个虚拟键的具体使用情况根据各人编译器或IDE等的不同而有所差异。下面是一个实现按Esc键就输出Esc的样例程序:
- #include
- #include
- #include
- #include
- #define true 1
- #define false 0
-
- int main()
- {
- HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
- INPUT_RECORD keyrec;
- DWORD res;
- for (;;)
- {
- ReadConsoleInput(handle_in, &keyrec, 1, &res);
- if (keyrec.EventType == KEY_EVENT)
- {
- if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
- {
- printf("Esc ");
- }
- }
- }
- return 0;
- }
在上面的样例程序中,当你按下Esc键后又马上释放,程序会输出两次Esc,因为有两次事件的虚拟键代码都是Esc键的代码,一次是按下,一次是释放。如果要实现按下键后出现反应,释放不出现反应,那么将上例程序中第18行代码的条件改成
- if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE
- && keyrec.Event.KeyEvent.bKeyDown == true)
就行了。
根据控制键的状态我们可以实现不同的状态输出不同的值以及组合键的实现,下面的样例程序在大写锁定打开时输入A键则输出大写字母A,否则输出小写字母a。而在Shift键被按下的状态是则输出Shift+A以及Shift+a。样例程序如下
- #include
- #include
- #include
- #include
- #define true 1
- #define false 0
-
- int main()
- {
- HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
- INPUT_RECORD keyrec;
- DWORD res;
- for (;;)
- {
- ReadConsoleInput(handle_in, &keyrec, 1, &res);
- if (keyrec.EventType == KEY_EVENT)
- {
- if (keyrec.Event.KeyEvent.wVirtualKeyCode == 'A'
- && keyrec.Event.KeyEvent.bKeyDown == true)
- {
- if (keyrec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
- {
- printf("Shift+");
- }
- if (keyrec.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON)
- {
- printf("A ");
- }
- else
- {
- printf("a ");
- }
- }
- }
- }
- return 0;
- }
由上例需要了解到的是,各个控制键状态的的确定并不是使用等于符号==而是按位与&运算符,因为在同一时刻可能有多种控制键状态值,比如各种锁定都被打开且各种控制键也被同时按下。使用&运算符则显得尤其高明,方便查询各个控制键的状态而不使之出现冲突。呵呵,不服不行啊,感慨一下,还是要多学习一下别人高明的地方,比如灵活运用位运算符实现各种功能等等······
八:鼠标事件
上次讲的是键盘事件,这次我们介绍鼠标事件。下面先介绍下鼠标事件的结构体以及相关信息。
- typedef struct _MOUSE_EVENT_RECORD
- {
- COORD dwMousePosition;
- DWORD dwButtonState;
- DWORD dwControlKeyState;
- DWORD dwEventFlags;
- } MOUSE_EVENT_RECORD;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
下面给一个样例程序,实现在控制台窗口缓冲区的最下面一行显示当前鼠标在缓冲区的坐标,单击左键在当前鼠标位置输出字母A,单击右键则输出字母B,双击任何鼠标键退出的功能。程序如下:
- #include
- #include
- #include
-
- HANDLE handle_in;
- HANDLE handle_out;
- CONSOLE_SCREEN_BUFFER_INFO csbi;
-
- void DisplayMousePosition(COORD pos);
-
- void gotoxy(int x, int y);
-
- int main()
- {
- handle_in = GetStdHandle(STD_INPUT_HANDLE);
- handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
- INPUT_RECORD mouserec;
- DWORD res;
- COORD pos;
- COORD size = {80, 25};
- GetConsoleScreenBufferInfo(handle_out, &csbi);
- SetConsoleScreenBufferSize(handle_out, size);
- for (;;)
- {
- ReadConsoleInput(handle_in, &mouserec, 1, &res);
- pos = mouserec.Event.MouseEvent.dwMousePosition;
- gotoxy(0, 24);
- DisplayMousePosition(pos);
- if (mouserec.EventType == MOUSE_EVENT)
- {
- gotoxy(pos.X, pos.Y);
-
- if (mouserec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
- {
- putchar('A');
- }
-
- if (mouserec.Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
- {
- putchar('B');
- }
-
- if (mouserec.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
- {
- break;
- }
- }
- }
- CloseHandle(handle_out);
- CloseHandle(handle_in);
- return 0;
- }
-
- void DisplayMousePosition(COORD pos)
- {
- COORD dis = {0, 24};
- WORD att = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
- GetConsoleScreenBufferInfo(handle_out, &csbi);
- printf("X = %3d, Y = %3d", (int)pos.X, (int)pos.Y);
- FillConsoleOutputAttribute(handle_out, att, 16, dis, NULL);
- return;
- }
-
- void gotoxy(int x, int y)
- {
- COORD pos = {x, y};
- SetConsoleCursorPosition(handle_out, pos);
- }
附上用本程序写的Hello world!的图:
注意:当使用system函数后鼠标事件无法正常发生。