在控制台中,高度和宽度的比是 2:1,所以设置控制台光标位置的时候,需要将宽度*2。在使用数组处理逻辑的时候, x 代表的是行数,y 代表的是列数,但是在控制台中,x 代表的是列数,y 代表的是行数。在具体的使用过程中,为了让数组和控制台的显示对应,通常需要调换 x 和 y 的位置,或者就用 x 代表列数,y 代表行数。

1
2
3
4
5
6
7
8
9
/*       数组             控制台
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 * * * * * 0 0 * 0 0 0 0 0
0 0 0 0 0 0 0 0 * 0 0 0 0 0
0 0 0 0 0 0 0 0 * 0 0 0 0 0
0 0 0 0 0 0 0 0 * 0 0 0 0 0
0 0 0 0 0 0 0 0 * 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
*/

完成控制台的鼠标事件:根据控制台中鼠标的位置显示出坐标,按左键打印出一个图形,右键擦除图形。

程序中,我们用 x 表示控制台中的横轴,显示列数,用 y 表示控制台中的纵轴,显示行数。当按下鼠标左键时,具体打印的位置是 x/2 的位置,否则打印的图形与鼠标就不重合,而是在鼠标右边两倍距离处。

1
2
3
4
5
6
7
8
9
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 添加 windows.h 头文件使用其中的函数
#include <windows.h>
#include <iostream>
// 在指定的坐标使用指定的颜色打印指定的字符
void WriteChar(short x, short y, WORD color, const char* s)
{
// 句柄: 在windwos中句柄用于标识某一种东西,这个例子中,句柄
// 被用于标识当前控制台的输出缓冲区,用于显示具体的内容
HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

// 通过函数的调用实现移动光标到指定位置
// 1: 想要修改的是哪一个输出缓冲区的光标位置
// 2: 想要将光标移动到控制台的哪一个位置
COORD pos = { x * 2, y };
SetConsoleCursorPosition(OutputHandle, pos);

// 为接下来需要打印的文字提供颜色,可以使用 RGB 搭配出一些简单
// 的颜色,不要使用较暗的颜色,应该选用亮色(黄色、绿色、白的)
SetConsoleTextAttribute(OutputHandle, color);

// 打印指定的图形
printf(s);
}

// 隐藏光标
void HindCursor(bool Hide = false)
{
// 句柄: 在windwos中句柄用于标识某一种东西,这个例子中,句柄
// 被用于标识当前控制台的输出缓冲区,用于显示具体的内同
HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);

// 定义结构体,用于保存光标的信息,参数二表示是否显示
CONSOLE_CURSOR_INFO Cursor = { 1, Hide };

// 调用函数设置光标的属性
SetConsoleCursorInfo(OutputHandle, &Cursor);
}

int main()
{
HindCursor(); // 隐藏光标
// 获取控制台输入缓冲区的句柄
HANDLE InputHandle = GetStdHandle(STD_INPUT_HANDLE);

// 开启鼠标事件的接受: ENABLE_MOUSE_INPUT
SetConsoleMode(InputHandle, ENABLE_MOUSE_INPUT);

DWORD Number = 0;
// 用于保存读取到的事件
INPUT_RECORD InputRecord = { 0 };

// 编写一个循环,不断的获取当前鼠标的事件
// - 1: 想要读取哪一个控制台的输入事件
// - 2: 一个结构体,保存了获取到的输入事件
// - 3: 数量,表示提供的结构体有几个(1)
// - 4: 当前读取到了几个事件
while (ReadConsoleInput(InputHandle, &InputRecord, 1, &Number))
{
// 接受的事件不止有鼠标类型,所以需要进行判断
if (InputRecord.EventType == MOUSE_EVENT)
{
// 获取到鼠标的坐标
COORD MouseCoord = InputRecord.Event.MouseEvent.dwMousePosition;

// 为所有的鼠标事件进行输出坐标的处理
CHAR Buffer[0x100] = { 0 };
// printf 将格式化后的内容填充控制台输出中
// 将格式化后的内容填充到提供的缓冲区中
sprintf_s(Buffer, "(%3d, %3d)", MouseCoord.X, MouseCoord.Y);
// 始终打印在屏幕的 0,0位置
WriteChar(0, 0, 0xF, Buffer);


// 通常来讲,鼠标的绘制应该直接反映在与绘图相关的数组中,
// 数组在游戏中扮演的地图,绘制的图形可以是障碍物或者事物。

// 鼠标事件有非常多,我们可以单独响应某一个事件
if (InputRecord.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
// 鼠标的左键按下了,就执行这里
WriteChar(MouseCoord.X / 2, MouseCoord.Y, 0xF, "●");
}
else if (InputRecord.Event.MouseEvent.dwButtonState == RIGHTMOST_BUTTON_PRESSED)
{
// 鼠标的左键按下了,就执行这里
WriteChar(MouseCoord.X / 2, MouseCoord.Y, 0xF, " ");
}

}
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 如果控制台无法接收到鼠标事件,就进行设置: 控制台标题右键 -> 属性 ->
// 选项 -> 取消快速编辑模式的勾选。
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
return 0;
}