虚拟键代码

 

虚拟键代码

虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn

在Windows操作系统中,虚拟键代码(Virtual-Key Codes)是一组用来表示键盘上按键的数值。这些代码通常用于Windows API函数,以便程序能够识别和处理键盘输入。
虚拟键代码是按键的物理位置定义的,而不是按字符本身定义的。这意味着,无论用户的键盘布局如何,同一物理按键的虚拟键代码都是相同的。例如,无论用户使用的是美式键盘、德式键盘还是日式键盘,字母 'A' 键的虚拟键代码都是 `VK_A`。
虚拟键代码通常以 `VK_` 开头,后面跟着一个或多个大写字母,表示特定的按键。例如:
- `VK_A` 表示 'A' 键。
- `VK_B` 表示 'B' 键。
- `VK_SPACE` 表示空格键。
- `VK_RETURN` 表示回车键。
- `VK_ESCAPE` 表示 ESC 键。
- `VK_UP` 表示向上箭头键。
- `VK_DOWN` 表示向下箭头键。
- `VK_LEFT` 表示向左箭头键。
- `VK_RIGHT` 表示向右箭头键。
- `VK_F1` 到 `VK_F12` 表示功能键 F1 到 F12。
在程序中,可以通过 `GetAsyncKeyState`、`GetKeyState` 或 `TranslateMessage` 等Windows API函数来检测虚拟键代码,从而判断用户是否按下了某个键。
 

if (KEY_PRESS(VK_UP) && ps->_SNAKE_DIR != DOWN)
{
    ps->_SNAKE_DIR = UP;
}

这里的 `KEY_PRESS(VK_UP)` 是一个宏或函数,用来检查用户是否按下了向上箭头键(`VK_UP`)。如果按下了,并且蛇当前的方向不是向下(`DOWN`),则将蛇的方向设置为向上(`UP`)。
这些虚拟键代码使得开发者能够以一种与键盘布局无关的方式处理键盘输入,从而编写出更加通用和易于移植的软件。
简单的说虚拟键代码的目的就是,进行识别是否按键

封装一个宏

我们封装一个宏,进行虚拟键代码的判断

#define KEY_PRESS(vk) (GetAsyncKeyState(vk)&1?1:0)

宏 `KEY_PRESS(vk)` 是一个用于检测指定虚拟键 `vk` 是否被按下的辅助宏。它使用了 `GetAsyncKeyState` 函数,这是Windows API中的一个函数,用于检查异步键盘输入的状态。


下面是宏 `KEY_PRESS(vk)` 的详细解释:
- `GetAsyncKeyState(vk)`:这个函数接受一个虚拟键代码 `vk` 作为参数,并返回该键的异步键状态。返回值是一个16位的整数,其中第15位(从最低位开始的最高位)表示该键是否被按下。如果该位为1,则键被按下;如果为0,则键没有按下。


- `&1`:这是一个位运算符,用于对 `GetAsyncKeyState(vk)` 的返回值进行按位与操作。这里 `1` 表示二进制的最低位为1,其他位为0。因此,`&1` 操作实际上是在检查

`GetAsyncKeyState(vk)` 返回值的第15位是否为1。


- `? :`:这是C语言中的三元条件运算符。如果 `GetAsyncKeyState(vk)&1` 的结果为真(非零),则表达式的值为 `1`,表示键被按下;如果为假(零),则表达式的值为 `0`,表示键没有被按下。


综上所述,`KEY_PRESS(vk)` 宏的目的是简化对 `GetAsyncKeyState` 函数的调用,并返回一个布尔值(0或1),指示指定的虚拟键 `vk` 是否被按下。在您的代码中,这个宏被用于检测用户的键盘输入,并根据这些输入来更新蛇的方向或游戏状态。
 

按键信息(贪吃蛇为例进行举例)

//蛇的运行逻辑
void Snake_RunGame(pSnake_State ps)
{
	do
	{
		//打印分数
		Snake_Cursor_Position(90, 20);
		wprintf(L"当前的得分是:%d", ps->_SNAKE_SCORE);

		Snake_Cursor_Position(90, 24);
		wprintf(L"一个食物的分数是:%d", ps->_SNAKE_ONE_FOOD);
		if (KEY_PRESS(VK_UP) && ps->_SNAKE_DIR != DOWN)
		{
			ps->_SNAKE_DIR = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_SNAKE_DIR != UP)
		{
			ps->_SNAKE_DIR = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_SNAKE_DIR != RIGHT)
		{
			ps->_SNAKE_DIR = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_SNAKE_DIR != LEFT)
		{
			ps->_SNAKE_DIR = RIGHT;
		}
		if (KEY_PRESS(VK_ESCAPE))//退出
		{
			ps->_SNAKE_STATE = KILL_ESE;
		}
		if (KEY_PRESS(VK_F4))//减速
		{
			if (ps->_SNAKE_ONE_FOOD > 10)
			{
				ps->_SNAKE_SLEEP_TIME += 30;
				ps->_SNAKE_ONE_FOOD = ps->_SNAKE_ONE_FOOD - 5;
			}
		}
		if (KEY_PRESS(VK_F3))//加速
		{
			if (ps->_SNAKE_ONE_FOOD < 45)
			{
				ps->_SNAKE_SLEEP_TIME -= 30;
				ps->_SNAKE_ONE_FOOD = ps->_SNAKE_ONE_FOOD + 5;
			}
		}
		if (KEY_PRESS(VK_SPACE))//暂停
		{
			SNAKEVK_SPACE();
		}
		//蛇的移动
		Snake_move(ps);
		//蛇的每次移动的休眠时间
		Sleep(ps->_SNAKE_SLEEP_TIME);

	} while (ps->_SNAKE_STATE == OK);
}

这段代码定义了一个函数 `Snake_RunGame`,它实现了蛇形游戏的主要运行逻辑。这个函数包含了蛇的移动、用户输入的检测、得分的更新以及游戏速度的控制。
下面是代码的解释:


1. `Snake_RunGame` 函数接受一个指向 `Snake_State` 结构的指针 `ps`,这个结构包含了蛇的状态信息,如头节点、状态、休息时间、得分等。


2. 函数使用一个 `do-while` 循环来持续运行游戏,直到蛇的状态不再是 `OK`(例如,蛇撞墙或吃到自己时)。


3. 在循环内部,首先使用 `Snake_Cursor_Position` 和 `wprintf` 函数打印当前得分和一个食物的分数。


4. 接下来,使用 `KEY_PRESS` 宏(或函数)来检测用户的键盘输入。根据用户按下的键(上、下、左、右箭头键),更新蛇的方向。如果蛇当前不是朝相反方向移动,蛇的方向会被更新。


5. 如果用户按下 `ESC` 键,游戏状态被设置为 `KILL_ESE`,表示游戏结束。


6. 如果用户按下 `F4` 键,游戏速度会减慢,蛇的休息时间增加,同时每个食物的分数减少。


7. 如果用户按下 `F3` 键,游戏速度会加快,蛇的休息时间减少,同时每个食物的分数增加。


8. 如果用户按下空格键,游戏会暂停。这可能是通过调用一个名为 `SNAKEVK_SPACE` 的函数实现的,但这个函数在提供的代码片段中没有定义。


9. `Snake_move` 函数被调用来处理蛇的移动逻辑。这个函数可能会更新蛇的位置,检查是否有食物被吃掉,以及蛇是否撞墙或吃到自己。


10. `Sleep` 函数用于控制游戏的更新速度,根据 `ps->_SNAKE_SLEEP_TIME` 的值来暂停一段时间。


11. `do-while` 循环的条件是蛇的状态为 `OK`,如果蛇的状态变为其他值(如 `KILL_ESE`),循环结束,游戏结束。


这个函数是蛇形游戏的核心部分,它负责处理游戏的主要逻辑和用户交互。在实际的游戏中,`Snake_move` 函数的实现细节对于游戏的行为至关重要。
 

这里代码有些函数是写完直接进行调用的,下面我会一一进行解释

  • 26
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安卓的虚拟功能可以通过使用系统提供的API来实现。以下是一个简单的实现示例: 1. 在布局文件中添加一个包含虚拟的视图: ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 其他视图 --> <LinearLayout android:id="@+id/keyboard_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_alignParentBottom="true"> <Button android:id="@+id/back_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回"/> <Button android:id="@+id/home_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="主页"/> <Button android:id="@+id/recent_apps_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="最近应用"/> </LinearLayout> </RelativeLayout> ``` 2. 在Activity的onCreate()方法中获取虚拟视图和按钮对象: ```java LinearLayout keyboardLayout = (LinearLayout) findViewById(R.id.keyboard_layout); Button backButton = (Button) findViewById(R.id.back_button); Button homeButton = (Button) findViewById(R.id.home_button); Button recentAppsButton = (Button) findViewById(R.id.recent_apps_button); ``` 3. 为每个按钮对象添加点击事件监听器,并在事件处理方法中调用系统提供的API来模拟按事件: ```java backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)); dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)); } }); homeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); startActivity(intent); } }); recentAppsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_RECENTS); startActivity(intent); } }); ``` 在这个示例中,backButton模拟了“返回”的按下和释放事件,homeButton启动了主屏幕Activity,而recentAppsButton启动了最近使用的应用程序菜单。您可以根据自己的需要添加更多按钮和事件处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值