C++ 获取鼠标点击位置
1.检测鼠标点击事件
GetAsyncKeyState函数可以检测按键点击事件
这里是它的函数原型：
SHORT_stdcall GetAsyncKeyState(int vKey);
我们首先要根据这个函数定义一个宏KEY_DOWN，这样可以方便以后的调用
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
常量名				   对应按键						取值
—————————————————————————————————————————————————————————
VK_LBUTTON             鼠标左键                      0x01
VK_RBUTTON             鼠标右键                      0x02
VK_CANCEL              Ctrl + Break                  0x03
VK_MBUTTON             鼠标中键                      0x04
VK_BACK                Backspace 键       		     0x08
VK_TAB                 Tab 键                        0x09
VK_RETURN              回车键                        0x0D
VK_SHIFT               Shift 键                      0x10
VK_CONTROL             Ctrl 键                       0x11
VK_MENU                Alt 键                        0x12
VK_PAUSE               Pause 键                      0x13
VK_CAPITAL             Caps Lock 键                  0x14
VK_ESCAPE              Esc 键                        0x1B
VK_SPACE               空格键         				 0x20
VK_PRIOR               Page Up 键                    0x21
VK_NEXT                Page Down 键                  0x22
VK_END                 End 键                        0x23
VK_HOME                Home 键                       0x24
VK_LEFT                左箭头键                      0x25
VK_UP                  上箭头键                      0x26
VK_RIGHT               右箭头键                      0x27
VK_DOWN                下箭头键                      0x28
VK_SNAPSHOT            Print Screen 键               0x2C
VK_Insert              Insert 键                     0x2D
VK_Delete              Delete 键                     0x2E
'0' – '9'              数字 0 - 9             0x30 - 0x39
'A' – 'Z'              字母 A - Z             0x41 - 0x5A
VK_LWIN                左WinKey(104键盘才有)         0x5B
VK_RWIN                右WinKey(104键盘才有)         0x5C
VK_APPS                AppsKey(104键盘才有)          0x5D
VK_NUMPAD0            小键盘 0 键                    0x60
VK_NUMPAD1            小键盘 1 键                    0x61
VK_NUMPAD2            小键盘 2 键                    0x62
VK_NUMPAD3            小键盘 3 键                    0x63
VK_NUMPAD4            小键盘 4 键                    0x64
VK_NUMPAD5            小键盘 5 键                    0x65
VK_NUMPAD6            小键盘 6 键                    0x66
VK_NUMPAD7            小键盘 7 键                    0x67
VK_NUMPAD8            小键盘 8 键                    0x68
VK_NUMPAD9            小键盘 9 键                    0x69
VK_F1 - VK_F24        功能键F1 – F24          0x70 - 0x87
VK_NUMLOCK            Num Lock 键                   0x90
VK_SCROLL             Scroll Lock 键                0x91
这个函数可以用来检测鼠标左键的按下，我们就需要这个，先来测试一下效果

#include <windows.h>                			//GetAsyncKeyState所需头文件
#include <iostream>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)  //用来检测按键的点击事件
int main() {
	//----------移除快速编辑模式(对于win10用户)----------
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);
	//----------循环检测----------
	while(1) {                      			//循环检测
		if(KEY_DOWN(VK_LBUTTON)) {  			//鼠标左键按下
			printf("key down!\n");
		}
		Sleep(20);                  			//等待20毫秒，减少CPU占用
	}
	return 0;
}

可以看到，每次我们点击鼠标左键都会输出key down!这就说明我们的程序成功了。当然，如果你对其他的按键检测感兴趣，你也可以试试其他的。

那么接下来接下来就是获取鼠标点击时的位置了。

2.获取鼠标位置
那么如何获取鼠标的位置呢？C++为我们提供了GetCursorPos这个函数，它可以用来获取鼠标在屏幕上的位置。这个函数需要提供一个POINT类型的地址，像下面这样：
POINT p;
GetCursorPos(&p);
POINT类型包含int x和int y两个变量，通过GetCursorPos函数就可以获取鼠标的位置，代码很简单，先来看一下效果：
#include <windows.h>                			//所需头文件
#include <iostream>
POINT p;
int main() {
	//----------循环检测----------
	while(1) {
		GetCursorPos(&p);                       //获取鼠标在屏幕上的位置
		printf("(%d,%d)\n",p.x,p.y);
		Sleep(20);                  			//等待20毫秒，减少CPU占用
	}
	return 0;
}
现在我们已经完成了已经完成了第二步，然后我们就要获取鼠标点击位置了。

3.获取鼠标点击位置
这个也是分简单，我们只需要把刚才的两段代码合起来就行了。
#include <windows.h>                			//GetAsyncKeyState所需头文件
#include <iostream>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)  //用来检测按键的点击事件
POINT p;
int main() {
	//----------移除快速编辑模式(对于win10用户)----------
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);

	//----------循环检测----------
	while(1) {                      			//循环检测
		if(KEY_DOWN(VK_LBUTTON)) {  			//鼠标左键按下
			GetCursorPos(&p);                   //获取鼠标在屏幕上的位置
			printf("key down (%d,%d)\n",p.x,p.y);
		}
		Sleep(100);                  			//等待100毫秒，减少CPU占用
	}
	return 0;
}
现在的程序已经基本上完成了 ，但是聪明的你可能会发现，这些坐标都是整个屏幕上的，如果我只想获取鼠标在该窗口上的位置呢？
这其实很简单，C++也为我们提供了这样一个函数ScreenToClient，它用来获取鼠标在指定窗口上的位置，其使用方法与之前的差不多：
POINT p;
GetCursorPos(&p);
ScreenToClient(h,&p);
在使用该函数之前，我们要先获取一下控制台窗口的句柄，用它来指定窗口；
HWND h=GetForegroundWindow();
其中，GetForegroundWindow函数用来获取最顶层窗口的句柄，这很适合我们的程序。
那么就先上代码吧！
#include <windows.h>                			//GetAsyncKeyState所需头文件
#include <iostream>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)  //用来检测按键的点击事件

POINT p;
HWND h=GetForegroundWindow();

int main() {

	//----------移除快速编辑模式(对于win10用户)----------
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);

	//----------循环检测----------
	while(1) {                      			//循环检测
		if(KEY_DOWN(VK_LBUTTON)) {  			//鼠标左键按下
			POINT p;
			GetCursorPos(&p);
			ScreenToClient(h,&p);               //获取鼠标在窗口上的位置
			printf("key down (%d,%d)\n",p.x,p.y);
		}
		Sleep(100);                  			//等待100毫秒，减少CPU占用
	}
	return 0;
}
现在输出的就是鼠标在控制台窗口上的位置了，但是如果需要像获取光标位置一样得到鼠标位置对应的控制台窗口上输出的坐标该怎样办呢？

首先我们要获取控制台字体的高和宽，像下面这样：
HANDLE hOutput;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFO consoleCurrentFont;
GetCurrentConsoleFont(hOutput, FALSE, &consoleCurrentFont);

GetStdHandle(STD_OUTPUT_HANDLE)用来获取窗口的输出句柄，将它储存到hOutput内,consoleCurrentFont用来储存字体的信息,用GetCurrentConsoleFont函数可以获取当前控制台的字体信息。获取字体的高和宽就像下面这样：

consoleCurrentFont.dwFontSize.X			//宽
consoleCurrentFont.dwFontSize.Y			//高
然后用鼠标的位置除以这两个之就行了，话不多说，先上代码。

成品
#include <windows.h>                			//GetAsyncKeyState所需头文件
#include <iostream>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)  //用来检测按键的点击事件

POINT p;
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
HWND h=GetForegroundWindow();
CONSOLE_FONT_INFO consoleCurrentFont;

int main() {
	//----------移除快速编辑模式(对于win10用户)----------
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);

	//----------循环检测----------
	while(1) {                      			//循环检测
		if(KEY_DOWN(VK_LBUTTON)) {  			//鼠标左键按下
			POINT p;
			GetCursorPos(&p);
			ScreenToClient(h,&p);               //获取鼠标在窗口上的位置
			GetCurrentConsoleFont(hOutput, FALSE, &consoleCurrentFont); //获取字体信息
			int x=p.x/=consoleCurrentFont.dwFontSize.X;
			int y=p.y/=consoleCurrentFont.dwFontSize.Y;
			printf("key down (%d,%d)\n",x,y);
		}
		Sleep(100);                  			//等待100毫秒，减少CPU占用
	}
	return 0;
}

4.1 实例：鼠标控制绘图
在写这个程序之前，我们先来了解一下几个函数：
void gotoxy(int x, int y) {
	COORD pos = {x,y};
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄
	SetConsoleCursorPosition(hOut, pos);//两个参数分别是指定哪个窗体，具体位置
}
这个函数用来移动光标来输出。
void HideTheCursor() {
	CONSOLE_CURSOR_INFO cciCursor;
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

	if(GetConsoleCursorInfo(hStdOut, &cciCursor)) {
		cciCursor.bVisible = FALSE;
		SetConsoleCursorInfo(hStdOut, &cciCursor);
	}
}
#include <windows.h>                			//GetAsyncKeyState所需头文件
#include <iostream>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)  //用来检测按键的点击事件

POINT p;
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
HWND h=GetForegroundWindow();
CONSOLE_FONT_INFO consoleCurrentFont;

//----------移动光标----------
void gotoxy(int x, int y) {
	COORD pos = {x,y};
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄
	SetConsoleCursorPosition(hOut, pos);//两个参数分别是指定哪个窗体，具体位置
}

//----------隐藏光标----------
void HideTheCursor() {
	CONSOLE_CURSOR_INFO cciCursor;
	HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

	if(GetConsoleCursorInfo(hStdOut, &cciCursor)) {
		cciCursor.bVisible = FALSE;
		SetConsoleCursorInfo(hStdOut, &cciCursor);
	}
}

int main() {
	HideTheCursor();                            //隐藏光标
	
	//----------移除快速编辑模式(对于win10用户)----------
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;
	SetConsoleMode(hStdin, mode);

	//----------循环检测----------
	while(1) {                      			//循环检测
		if(KEY_DOWN(VK_LBUTTON)) {  			//鼠标左键按下
			POINT p;
			GetCursorPos(&p);
			ScreenToClient(h,&p);               //获取鼠标在窗口上的位置
			GetCurrentConsoleFont(hOutput, FALSE, &consoleCurrentFont); //获取字体信息
			int x=p.x/=consoleCurrentFont.dwFontSize.X;
			int y=p.y/=consoleCurrentFont.dwFontSize.Y;
			gotoxy(x,y);                        //移动光标置鼠标位置
			printf("@");                        //在鼠标位置输出
		}
		Sleep(10);                  			//延时
	}
	return 0;
}
