前言:
Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外, 它同时也是⼀个很⼤的服务中⼼,调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程式达到开启视窗、描绘图形、使⽤周边设备等⽬的,由于这些函数服务的对象是应⽤程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应⽤程序编程接⼝。
本篇介绍的API主要针对下一篇贪吃蛇项目中用到的API
控制控制台程序窗口的指令:
平常我们win+R输入cmd后运⾏起来的⿊框程序其实就是控制台程序,我们可以通过一些命令实现对控制台程序实现一些简单的更改:
//更改窗⼝的⻓宽
mode con cols=100lines=30
//更改窗⼝的名字
title 改名字
那么我们该怎样在VS2022编译环境下使用这些命令呢?
system函数:
函数原型:int system(const char *command);
command
表示要执行的命令,该命令将由操作系统的控制台程序进行分析和执行包含头文件:<stdlib.h>
作用:在编译器环境下实现对操作系统的控制台程序的相关操作
(先了解,具体使用会在后续的贪吃蛇项目中实现)
COORD函数:
函数原型:
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;
包含头文件:<windows.h>
作用:表示⼀个字符在控制台屏幕上的坐标
//给结构体类型的变量pos赋值:
COORD pos = { 10, 15};//这的确是给结构体类型变量赋值的正确方式哈
GetStdHandle函数:
函数原型:HANDLE GetStdHandle(DWORD nStdHandle);
包含头文件:<windows.h>
作用:从⼀个特定的标准设备中获取(标准输⼊、标准输出或标准错误)中取得⼀个句柄,有了该句柄就有了对该设备输入、输出或错误进行修改的权限
①HANDLE是一个结构体类型的指针
②DWORD nStdHandle用于指定要获取的标准设备的类型,常用的标准设备类型包括:
STD_INPUT_HANDLE:标准输入设备
STD_OUTPUT_HANDLE:标准输出设备
STD_ERROR_HANDLE:标准错误设备
③函数的返回值是一个句柄,有了它你就获取了对于以上三种设备的操作权限,至于获取权限后可以干什么就得看你的需求了,我们在下面获得了控制台程序的标准输出设备的权限后可以利用GetConsoleCursorInfo函数对光标信息进行控制
一旦你获得了某个标准设备的权限,就可以根据个人需求选择适当的函数或方法来执行一些操作
有了某个权限后只能用来执行它这个权限规定范围内的操作
(比如我允许你在我电脑上玩游戏之类的但你不能更改我电脑的相关配置,我没给你这个权限)
如果你还不懂,往下看后面有对该函数的使用案例
//获取标准输出的句柄hOutput(有了它你就有了操作修改台光标信息等的权限)
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleCursorInfo函数:
函数原型:
BOOL WINAPI GetConsoleCursorInfo {
HANDLE hConsoleOutput ,
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
};
包含头文件:<windows.h>
作用:利用获取的控制台输出句柄(hConsoleOutput
)来控制光标(lpConsoleCursorInfo
:指向CONSOLE_CURSOR_INFO
结构体的指针,用于接收光标的信息)(想要控制还得用下面这个函数)
CONSOLE_CURSOR_INFO函数:
函数原型:
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
包含头文件:<windows.h>
作用:控制光标的大小dwise(取值范围为1到100之间的百分比)和是否可见vVisible (TRUE表示可见,FALSE表示不可见,默认可见)
//GetConsoleCursorInfo函数需要与CONSOLE_CURSOR_INFO函数配合使用:
hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备的句柄
CONSOLE_CURSOR_INFO CursorInfo; //定义结构体类型变量
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取当前光标信息(让系统知道)
CursorInfo.dwSize=50;//然后才能利用CursorInfo修改光标信息
SetConsoleCursorInfo函数:
函数原型:
BOOL WINAPI SetConsoleCursorInfo{
HANDLE hConsoleOutput,
constCONSOLE_CURSOR_INFO *lpConsoleCursorInfo
};
包含头文件:<windows.h>
作用:显示修改后的光标信息
!!!这里是上面四个函数的整体配合方式:
//操作光标的全部流程
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//获取权限
CONSOLE_CURSOR_INFO CursorInfo;//定义结构体类型变量
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
SetConsoleCursorPosition函数:
函数原型:
BOOL WINAPI SetConsoleCursorPosition{
HANDLE hConsoleOutput,
COORD pos
};
包含头文件:<windows.h>
作用:将光标位置设置到指定的位置
COORD pos = {10, 5};
//获取标准输出的句柄
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
为了便于设置光标的位置我们会自定义一个SetPos函数,它的使用方式如下:
//设置光标的坐标
void SetPos(shortx, shorty)
{
COORD pos = { x, y };
//获取标准输出的句柄(⽤来标识不同设备的数值)
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
}
#include <stdio.h> #include <windows.h> #include <stdbool.h> int main() { HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//获取权限 COORD pos = { 5,20 }; SetConsoleCursorPosition(hOutput, pos); int ch = getchar(); putchar(ch); return 0; }
可以看到初始输入(初始光标)的坐标已经从x=0,y=0变为了x=5,y=20...
GetAsyncKeyState函数:
函数原型:
SHORT GetAsyncKeyState(
intvKey
);
包含头文件:<windows.h>
作用:监控按键使用(按下/弹起)情况
详细作用:GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果 返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0
//如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1
#defineKEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
实例:监控部分键盘按键的使用
#include <stdio.h> #include <windows.h> //PRESS_KET 来检测vk这些虚拟键值对应的按键是否被按过 //如果按过返回1,未按过返回0 #define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0) int main() { while (1) { if (KEY_PRESS(0x30)) { printf("0\n"); } else if (KEY_PRESS(0x31)) { printf("1\n"); } else if (KEY_PRESS(0x32)) { printf("2\n"); } else if (KEY_PRESS(0x33)) { printf("3\n"); } else if (KEY_PRESS(0x34)) { printf("4\n"); } else if (KEY_PRESS(0x35)) { printf("5\n"); } else if (KEY_PRESS(0x36)) { printf("6\n"); } else if (KEY_PRESS(0x37)) { printf("7\n"); } else if (KEY_PRESS(0x38)) { printf("8\n"); } else if (KEY_PRESS(0x39)) { printf("9\n"); } } return 0; }
注意这里只能对主键盘(有字母的那个)中的数字按键进行监控,对于小键盘中的数字键,该函数并不能直接检测到其按下。
小拓展:
小键盘中的数字键实际上是通过发送键盘消息的方式来模拟的,而不是直接映射为键盘扫描码。因此,GetAsyncKeyState()
函数无法直接检测小键盘中的数字键,如果你想要检测小键盘中的数字键是否被按下,可以使用以下方法之一:
使用 GetKeyState()
函数:GetKeyState()
函数可以检测指定虚拟键的状态,包括小键盘中的数字键。你可以传递小键盘数字键对应的虚拟键码(如 VK_NUMPAD0
、VK_NUMPAD1
等)作为参数,然后检查返回值的最高位是否被设置(表示按键被按下)。
#include <stdio.h> #include <windows.h> //PRESS_KET 来检测vk这些虚拟键值对应的按键是否被按过 //如果按过返回1,未按过返回0 #define KEY_PRES(VK) ((GetKeyState(VK) & 0x8000) ? 1 : 0) int main() { while (1) { if (KEY_PRESS(0x60)) { printf("0\n"); } else if (KEY_PRESS(0x61)) { printf("1\n"); } else if (KEY_PRESS(0x62)) { printf("2\n"); } else if (KEY_PRESS(0x63)) { printf("3\n"); } else if (KEY_PRESS(0x64)) { printf("4\n"); } else if (KEY_PRESS(0x65)) { printf("5\n"); } else if (KEY_PRESS(0x66)) { printf("6\n"); } else if (KEY_PRESS(0x67)) { printf("7\n"); } else if (KEY_PRESS(0x68)) { printf("8\n"); } else if (KEY_PRESS(0x69)) { printf("9\n"); } } return 0; }
~over~