MapVirtualKey

本文详细解析了Windows API中的MapVirtualKey函数,它用于键码映射,包括将虚拟键码转为扫描码、字符值或反之。讲解了不同参数组合下函数的工作原理,以及其在处理左右键区分和字符翻译中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数功能:该函数将一虚拟键码翻译(映射)成一扫描码或一字符值,或者将一扫描码翻译成一虚拟键码

函数原型:UINT MapVirtualKey(UINT uCode,UINT uMapType)

语法

UINT WINAPI MapVirtualKey(
  _In_  UINT uCode,
  _In_  UINT uMapType
);

参数

uCode:定义一个键的扫描码或虚拟键码。该值如何解释依赖于uMapType参数的值。

uMapType:定义将要执行的翻译。该参数的值依赖于uCode参数的值。取值如下:

MAPVK_VK_TO_VSC(0:代表uCode是一虚拟键码且被翻译为一扫描码。若一虚拟键码不区分左右,则返回左键的扫描码。若未进行翻译,则函数返回0。

MAPVK_VSC_TO_VK(1)uCode参数是一个扫描码,被翻译成一个不区分左右键的虚拟键码。如果没有翻译,该函数返回 0。

MAPVK_VK_TO_CHAR(2)uCode参数是一个虚拟键码,在返回值的低位字中被翻译成一个未移位的字符值。通过设置返回值的最高位来指示死键(变音符号)。如果没有翻译,该函数返回 0。

MAPVK_VSC_TO_VK_EX(3):代表uCode为一扫描码且被翻译为区分左右键的虚拟键码。若未进行翻译,则函数返回0。

MAPVK_VK_TO_VSC_EX(4):Windows Vista 及更高版本: uCode参数是一个虚拟键码,并被转换为扫描码。如果是不区分左右键的虚拟键码,则返回左键扫码。如果扫描码是扩展扫描码,则uCode值的高字节可以包含0xe0或0xe1来指定扩展扫描码。如果没有翻译,该函数返回 0。

返回值:返回值可以是一扫描码,或一虚拟键码,或一字符值,这完全依赖于不同的uCode和uMapType的值。若未进行翻译,则函数返回0。

注意事项

应用程序可以使用MapVirtualKey将扫描码转换为虚拟键码常量VK_SHIFT(shift键)VK_CONTROL(ctrl键)VK_MENU(alt键),反之亦然。这些翻译不区分 SHIFT、CTRL 或 ALT 键的左右实例。应用程序可以通过调用MapVirtualKey函数时将uCode参数

应用程序可以通过调用MapVirtualKey并将uCode设置为以下虚拟键代码常量之一来获取与这些键之一的左侧或右侧实例对应的扫描代码:

  • VK_LSHIFT
  • VK_RSHIFT
  • VK_LCONTROL
  • VK_RCONTROL
  • VK_LMENU
  • VK_RMENU

应用程序只能通过GetKeyboardStateSetKeyboardStateGetAsyncKeyStateGetKeyStateMapVirtualKeyMapVirtualKeyEx函数使用这些左右区分常量。有关虚拟键码的完整列表,请参阅虚拟键码

Windows CE:Windows CE仅支持uMapType参数取值为2的情况,即将虚拟键映射为未被移位的字符。

速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:1.O及以L版本;头文件:winuser.h;库文件:user32.lib;在Windows NT上实现为Unicode和ANSI两种版本。

#include <windows.h> #include <iostream> #include <fstream> #include <string> #include <conio.h> using namespace std; const string CONFIG_FILE = "key_config.txt"; const string DEFAULT_KEY = "F8"; // 虚拟键映射表 const unordered_map<string, SHORT> vkMap = { {"A", 0x41}, {"B", 0x42}, {"C", 0x43}, {"D", 0x44}, {"E", 0x45}, {"F", 0x46}, {"G", 0x47}, {"H", 0x48}, {"I", 0x49}, {"J", 0x4A}, {"K", 0x4B}, {"L", 0x4C}, {"M", 0x4D}, {"N", 0x4E}, {"O", 0x4F}, {"P", 0x50}, {"Q", 0x51}, {"R", 0x52}, {"S", 0x53}, {"T", 0x54}, {"U", 0x55}, {"V", 0x56}, {"W", 0x57}, {"X", 0x58}, {"Y", 0x59}, {"Z", 0x5A}, {"0", 0x30}, {"1", 0x31}, {"2", 0x32}, {"3", 0x33}, {"4", 0x34}, {"5", 0x35}, {"6", 0x36}, {"7", 0x37}, {"8", 0x38}, {"9", 0x39}, {"F1", VK_F1}, {"F2", VK_F2}, {"F3", VK_F3}, {"F4", VK_F4}, {"F5", VK_F5}, {"F6", VK_F6}, {"F7", VK_F7}, {"F8", VK_F8}, {"F9", VK_F9}, {"F10", VK_F10}, {"F11", VK_F11}, {"F12", VK_F12}, {"SPACE", VK_SPACE}, {"ENTER", VK_RETURN}, {"ESC", VK_ESCAPE}, {"LEFT", VK_LEFT}, {"RIGHT", VK_RIGHT}, {"UP", VK_UP}, {"DOWN", VK_DOWN}, {"CTRL", VK_CONTROL}, {"ALT", VK_MENU}, {"SHIFT", VK_SHIFT}, {"TAB", VK_TAB}, {"CAPSLOCK", VK_CAPITAL}, {"BACKSPACE", VK_BACK} }; // 获取键名对应的虚拟键 SHORT GetKeyCode(const string& keyName) { auto it = vkMap.find(keyName); if (it != vkMap.end()) { return it->second; } return 0; } // 获取虚拟键对应的键名 string GetKeyName(SHORT vkCode) { for (const auto& pair : vkMap) { if (pair.second == vkCode) { return pair.first; } } return ""; } // 初始化配置文件 void InitConfigFile() { ofstream file(CONFIG_FILE); if (file.is_open()) { file << DEFAULT_KEY; file.close(); } } // 读取配置的键名 string ReadConfigKey() { ifstream file(CONFIG_FILE); string keyName; if (file.is_open()) { file >> keyName; file.close(); } return keyName.empty() ? DEFAULT_KEY : keyName; } // 保存键名到配置文件 void SaveConfigKey(const string& keyName) { ofstream file(CONFIG_FILE); if (file.is_open()) { file << keyName; file.close(); } } // 等待用户按键并返回键名 string WaitForUserKeyPress() { cout << "请按下要设置的键 (按ESC取消)...\n"; string lastKey; while (true) { if (_kbhit()) { int ch = _getch(); // 处理功能键 if (ch == 0 || ch == 0xE0) { int ext = _getch(); SHORT vkCode = MapVirtualKey(ext, MAPVK_VSC_TO_VK); lastKey = GetKeyName(vkCode); if (!lastKey.empty()) { cout << "检测到按键: " << lastKey << endl; } } // 处理普通键 else { SHORT vkCode = MapVirtualKey(ch, MAPVK_VSC_TO_VK); lastKey = GetKeyName(vkCode); if (!lastKey.empty()) { cout << "检测到按键: " << lastKey << endl; } // ESC键取消 if (vkCode == VK_ESCAPE) { return ""; } } // 等待按键释放 while (_kbhit()) { _getch(); } // 返回最后一个有效按键 if (!lastKey.empty()) { return lastKey; } } Sleep(10); } } // 模拟按键按下 void SimulateKeyPress(SHORT vkCode) { INPUT input[2] = { {0}, {0} }; // 按下键 input[0].type = INPUT_KEYBOARD; input[0].ki.wVk = vkCode; // 释放键 input[1].type = INPUT_KEYBOARD; input[1].ki.wVk = vkCode; input[1].ki.dwFlags = KEYEVENTF_KEYUP; SendInput(2, input, sizeof(INPUT)); } // 串口监听函数 void MonitorSerialPort(SHORT vkCode) { HANDLE hSerial = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hSerial == INVALID_HANDLE_VALUE) { cout << "无法打开串口COM3\n"; return; } // 配置串口 DCB dcb = { 0 }; dcb.DCBlength = sizeof(DCB); if (!GetCommState(hSerial, &dcb)) { cout << "获取串口状态失败\n"; CloseHandle(hSerial); return; } dcb.BaudRate = CBR_9600; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; if (!SetCommState(hSerial, &dcb)) { cout << "设置串口状态失败\n"; CloseHandle(hSerial); return; } cout << "开始监听串口 (按ESC退出)...\n"; cout << "当串口开关按下时将模拟按下: " << GetKeyName(vkCode) << endl; char buffer; DWORD bytesRead; bool running = true; while (running) { if (ReadFile(hSerial, &buffer, 1, &bytesRead, NULL) && bytesRead > 0) { if (buffer == '1') { // 假设串口发送'1'表示开关按下 SimulateKeyPress(vkCode); } } // 检查是否按下ESC键 if (_kbhit() && _getch() == 27) { running = false; } Sleep(10); } CloseHandle(hSerial); } // 主菜单 void ShowMainMenu(const string& currentKey) { system("cls"); cout << "===== 串口按键模拟器 =====\n"; cout << "当前配置按键: " << currentKey << "\n\n"; cout << "1. 更改按键配置\n"; cout << "2. 开始监听串口\n"; cout << "3. 退出程序\n"; cout << "请选择: "; } int main() { // 初始化配置文件 ifstream testFile(CONFIG_FILE); if (!testFile.good()) { InitConfigFile(); } testFile.close(); string currentKey = ReadConfigKey(); bool running = true; while (running) { ShowMainMenu(currentKey); int choice; cin >> choice; switch (choice) { case 1: { // 更改按键配置 string newKey = WaitForUserKeyPress(); if (!newKey.empty()) { cout << "要将按键配置更改为 " << newKey << " 吗? (Y/N): "; char confirm; cin >> confirm; if (toupper(confirm) == 'Y') { SaveConfigKey(newKey); currentKey = newKey; cout << "按键配置已更新\n"; } } else { cout << "取消更改\n"; } break; } case 2: // 开始监听串口 MonitorSerialPort(GetKeyCode(currentKey)); break; case 3: // 退出程序 running = false; break; default: cout << "无效选择\n"; break; } cout << "按任意键继续..."; _getch(); } return 0; }
最新发布
07-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值