重庆教育建设集团有限公司网站,菠菜网站开发一条龙,wordpress页眉颜色,做网站app要多少钱目录
前言
一、Scancode Map 的规范
二、禁用 CtrlAltDel 的方法及其缺陷
三、编程实现和测试
3.1 C 实现的简易修改工具
3.2 C# 实现的窗口工具
四、总结 本文属于原创文章#xff0c;转载请注明出处#xff1a;
https://blog.csdn.net/qq_59075481/article/details…目录
前言
一、Scancode Map 的规范
二、禁用 CtrlAltDel 的方法及其缺陷
三、编程实现和测试
3.1 C 实现的简易修改工具
3.2 C# 实现的窗口工具
四、总结 本文属于原创文章转载请注明出处
https://blog.csdn.net/qq_59075481/article/details/136104444。
前言
在 Ndr-LRPC Hook 和 WMsg Hook 等方法完善前网络上公开的禁用 CtrlAltDel 键的方法是使用 Scancode Map 键盘扫描码映射表这个方法本质上是利用微软提供的注册表设置来达到屏蔽的效果。这确实在前一阶段是较好的解决方案所以在更新完前两种方案后我不打算对这个方法避而不谈相反我觉得该方法可以用于更广泛的方面甚至许多键盘快捷键修改程序就利用了类似的方法。本文将就具体的实现细节给出通用修改工具以及谈谈这种方法存在优缺点。工具有两个一个是我重写的 C 简化实现另一个是基于 C# 的开源工具查阅资料时偶然发现。
一、Scancode Map 的规范
Scancode Map 注册表项位于注册表如下路径 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 它是 Keyboard Layout 子键下名为Scancode Map的二进制值项如果没有你可以新建一个。
这个值项可实现对键盘按键的映射。这里映射的意思可理解为“替换”可将任意一键替换成其它键或者禁用。
Scancode Map 注册表项具有类似下面的格式
以 16 进制表示可分为五个部分为了方便讲解相邻字节之间用逗号隔开。 Scancode Map 00,00,00,00,00,00,00,00,02,00,00,00,01,00, 02,00,00,00,00,00 前 8 个字节 表示版本信息号一般为 0。 紧接着的 4 个字节 表示映射键的总数 1。按照二进制的读写规则低位在左高位在右。02 00 00 00 这个数实际就是00 00 00 02 该用例表示当前修改 1 个键。 紧接着的 2 个字节 表示替换后按键的“扫描码”。如ESC 键的扫描码是 01 所以就表示 01 00 。再比如左 Ctrl 键扫描码是 1D 00, 而右 Ctrl 键是 1D E0 。 紧接着的 2 个字节表示原按键的“扫描码”格式同上。 最后以四个 00 结束8个也行。
键盘的按键扫描码可以参考下面这幅图已经按照书写格式排列 按键名称-扫描码对照表 图片来源https://www.bilibili.com/read/cv8001022/
二、禁用 CtrlAltDel 的方法及其缺陷
根据上面提供的信息我们了解到需要禁用 Ctrl Alt Del 键只禁用 Del 就可以了不需要修改左键原因是 Ctrl / Alt 需要经常用而 Del 用的频率较少。
经查表Del 键对应的扫描码是 53 E0所以按照规则我们只需要将 53 E0 映射为其他按键或者映射为空即可比如下图 注册表按键映射表 这张图是注册表中修改过后的结果圈出来的就是需要关注的的位置 02 表示总数加一连同后面 3 个 00一共四个字节后面两字节是替换的扫描码我这里替换成数字 14F 00。原键的扫描码是 53 E0。
这个方法优点就是实现简单。
当然这个方法缺陷很明显不可避免的按键要被无差别禁用Del 键却还有其他功能所以会影响使用体验。
三、编程实现和测试
那么如何通过代码来实现修改呢很简单就是读取注册表和修改注册表只不过需要按照字节序构建数据。
3.1 C 实现的简易修改工具
为了方便制作一个简易的测试工具我为工具定义了 config.cfg 配置文件的规则样例如下 # 此处填写要修改的总数当然程序写入注册表时按照规则注册表的记录总数比用户实际修改的个数多加1这在之前也介绍过。 [ReMapKeyNum] 3 # 修改的键的顺序 [MapKeyRank] 1 # 修改的键的原始扫描码格式十六进制两个字符。 [MapKeyOriCode] 1d00 # 修改的键的新扫描码格式十六进制两个字符。 [MapKeyNewCode] 1de0 [MapKeyRank] 2 [MapKeyOriCode] 3800 [MapKeyNewCode] 38e0 [MapKeyRank] 3 [MapKeyOriCode] 53e0 [MapKeyNewCode] 0000 配置文件放在任意位置均可目前已经实现功能的参数列表如下
/enumerate 解析注册表中重映射按键的数据该方法会逆编码原始按键名称不过目前未实现区分左右按键/setremap configFilePath指定一个路径作为配置文件路径配置文件按照规范书写程序将解析配置文件并用该配置文件覆盖注册表按键映射表/queryActiveKey动态查询键盘输入的按键的扫描码不区分左右按键这点需要改进/deleteAllMap删除整个注册表按键映射表恢复系统默认配置需要二次确认操作。注意该操作无法撤销删除/modifyDelKey删除注册表按键映射表中指定的条目。该命令首先解析所有条目信息随后通过输入要删除的 Item 编号即可实现删除/modifyInsertKey在指定的 Item 编号之后添加新的数据条目。需要手动输入三个参数第一个为原始按键扫描码第二个为修改后的按键扫描码第三个为 Item 编号/modifyAddKey不需要指定位置编号在结尾追加新的条目。/statusMap bEnable启用或禁用重映射键注册表项该操作通过将映射表标记为 DISABLED 来禁用整张表所以操作可以恢复status 参数为 0 表示禁用为 1 表示启用/makebackup备份注册表当前重映射表数据。该命令拷贝一个按照时间记录的注册表副本。/recoverMap backupTime恢复按照时间标签备份的副本该操作将覆盖当前的注册表按键映射表。/readbackup读取所有注册表备份按照时间标签列表显示
完整代码如下注意所有的修改除了备份数据其他操作对于大部分应用需要重启计算机生效
#include iostream
#include fstream
#include sstream
#include vector
#include Windows.h
#include iomanip// 定义宏
#define REGISTRY_KEY LSYSTEM\\CurrentControlSet\\Control\\Keyboard Layout
#define REGISTRY_VALUE_NAME LScancode Map
#define CONFIG_FILE_SECTION_REMAP_KEY_NUM [ReMapKeyNum]
#define CONFIG_FILE_SECTION_MAP_KEY_RANK [MapKeyRank]
#define CONFIG_FILE_SECTION_MAP_KEY_ORI_CODE [MapKeyOriCode]
#define CONFIG_FILE_SECTION_MAP_KEY_NEW_CODE [MapKeyNewCode]
#define BACKUP_KEY_PREFIX LScancode_Map_Back_
#define DESABLED_KEY_PREFIX L_DISABLED// 全局变量用于记录按键状态
int remainingKeys 0;
int remainingRounds 0;
int numKeys 0;
std::vectorstd::pairstd::string, DWORD keyNameValuePairs;// 解析注册表中的重映射信息
bool ParseRemapInfo(std::vectorstd::pairWORD, WORD remapInfo) {HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_READ, hKey) ERROR_SUCCESS) {DWORD bufferSize 0;DWORD dataType;if (RegQueryValueEx(hKey, REGISTRY_VALUE_NAME, NULL, dataType, NULL, bufferSize) ERROR_SUCCESS dataType REG_BINARY) {std::vectorBYTE buffer(bufferSize);if (RegQueryValueEx(hKey, REGISTRY_VALUE_NAME, NULL, NULL, buffer.data(), bufferSize) ERROR_SUCCESS) {DWORD totalRemappedKeys *(DWORD*)(buffer.data() 8) - 1;for (DWORD i 0; i totalRemappedKeys; i) {WORD remappedScanCode *(WORD*)(buffer.data() 12 i * 4);WORD originalScanCode *(WORD*)(buffer.data() 14 i * 4);remapInfo.emplace_back(originalScanCode, remappedScanCode);}}RegCloseKey(hKey);return true;}else {RegCloseKey(hKey);return false;}}return false;
}// 枚举当前重映射的按键并逆向转换扫描码为键名
void EnumerateRemappedKeys(std::vectorstd::pairWORD, WORD remapInfo) {std::cout Remapped keys:\n;CHAR remappedKeyName[30] { 0 }, originalKeyName[30] { 0 };WORD remappedScanCode 0, originalScanCode 0;int newKeyret 0, oldKeyret 0;for (size_t i 0; i remapInfo.size(); i) {newKeyret 0, oldKeyret 0;memset(remappedKeyName, 0, sizeof(remappedKeyName));memset(originalKeyName, 0, sizeof(originalKeyName));originalScanCode remapInfo[i].first;remappedScanCode remapInfo[i].second;newKeyret GetKeyNameTextA(remappedScanCode 16,remappedKeyName, sizeof(remappedKeyName) / sizeof(*remappedKeyName));oldKeyret GetKeyNameTextA(originalScanCode 16,originalKeyName, sizeof(originalKeyName) / sizeof(*originalKeyName));// 逆向转换扫描码为键名std::cout Item i 1 :\n;std::cout Remapped Scan Code: 0x std::hex remappedScanCode \n;std::cout Remapped Key Name: (newKeyret 0 ? remappedKeyName : (null)) \n;std::cout Original Scan Code: 0x std::hex originalScanCode \n;std::cout Original Key Name: (oldKeyret 0 ? originalKeyName : (null)) \n;}
}// 根据配置文件修改或添加重映射的按键
void ModifyRemappedKeys(const std::string configFile) {std::ifstream file(configFile);if (!file.is_open()) {std::cerr Failed to open config file: configFile std::endl;return;}std::string line;int totalRemappedKeys 0;WORD tempCode 0, theCode 0;std::vectorWORD originalScanCodes, newScanCodes;while (std::getline(file, line)) {if (line.empty() || line[0] #) // 绕过空行和注释continue;if (line.find(CONFIG_FILE_SECTION_REMAP_KEY_NUM) ! std::string::npos) {// 循环绕过多行注释或空行do{std::getline(file, line); // 读取包含总重映射按键数的下一行}while (line.empty() || line[0] #);std::istringstream iss(line);iss totalRemappedKeys;originalScanCodes.reserve(totalRemappedKeys);newScanCodes.reserve(totalRemappedKeys);}else if (line.find(CONFIG_FILE_SECTION_MAP_KEY_ORI_CODE) ! std::string::npos) {do {std::getline(file, line); // 读取包含原始扫描码的行} while (line.empty() || line[0] #);std::istringstream iss(line);std::string hexCode;iss hexCode;tempCode static_castWORD(std::stoi(hexCode, nullptr, 16));// stoi 读取时默认小端序会导致数据颠倒需要恢复一下theCode ((tempCode 0xFF) 8) | ((tempCode 8) 0xFF);originalScanCodes.push_back(theCode);}else if (line.find(CONFIG_FILE_SECTION_MAP_KEY_NEW_CODE) ! std::string::npos) {do {std::getline(file, line); // 读取包含新扫描码的行} while (line.empty() || line[0] #);std::istringstream iss(line);std::string hexCode;iss hexCode;tempCode static_castWORD(std::stoi(hexCode, nullptr, 16));// stoi 读取时默认小端序会导致数据颠倒需要恢复一下theCode ((tempCode 0xFF) 8) | ((tempCode 8) 0xFF);newScanCodes.push_back(theCode);}}if (originalScanCodes.size() ! totalRemappedKeys || newScanCodes.size() ! totalRemappedKeys) {std::cerr Invalid configuration file format. std::endl;return;}// 创建基于配置数据的缓冲区std::vectorBYTE buffer(20 totalRemappedKeys * 4, 0); // 头部20 字节 重映射按键数据*(DWORD*)(buffer.data() 8) totalRemappedKeys 1; // 记录个数 实际个数 1规则for (int i 0; i totalRemappedKeys; i) {std::cout OriKeyCode: 0x std::hex originalScanCodes[i] \t NewKeyCode: 0x std::hex newScanCodes[i] \n;// 写入数据到向量结构中*(WORD*)(buffer.data() 12 i * 4) newScanCodes[i];*(WORD*)(buffer.data() 14 i * 4) originalScanCodes[i];}// 修改注册表中的重映射按键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_SET_VALUE, hKey) ERROR_SUCCESS) {if (RegSetValueEx(hKey, REGISTRY_VALUE_NAME, 0, REG_BINARY, buffer.data(), buffer.size()) ERROR_SUCCESS) {std::cout Scancode Map updated successfully.\n;}else {std::cerr Failed to update Scancode Map.\n;}RegCloseKey(hKey);}else {std::cerr Failed to open registry key.\n;}
}// 钩子过程函数处理键盘输入消息
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {if (nCode HC_ACTION) {KBDLLHOOKSTRUCT* kbStruct reinterpret_castKBDLLHOOKSTRUCT*(lParam);if (wParam WM_KEYDOWN || wParam WM_SYSKEYDOWN) {CHAR keyName[256];if (GetKeyNameTextA(kbStruct-scanCode 16, keyName, sizeof(keyName)) 0) {keyNameValuePairs.emplace_back(keyName, kbStruct-scanCode);if (--remainingKeys 0) {std::cout Round completed.\n;if (--remainingRounds 0) {std::cout Maximum rounds reached.\n;std::cout Continuous Input:\n;for (const auto pair : keyNameValuePairs) {std::cout pair.first : 0x std::hex pair.second \n;}PostQuitMessage(0); // 退出消息循环}else {std::cout Continuous Input so far:\n;for (const auto pair : keyNameValuePairs) {std::cout pair.first : 0x std::hex pair.second \n;}keyNameValuePairs.clear();remainingKeys numKeys;std::cout \nPlease press numKeys keys per round.\n;}}}}}return CallNextHookEx(NULL, nCode, wParam, lParam);
}// 监视键盘输入以查询给定键的扫描码
void QueryScanCodeForKey() {// 键入循环参数do {std::cout Please press numbers of keys per round, and a maximum of rounds (for at least 1 key for 1 round). std::endl;std::cin numKeys remainingRounds;} while (numKeys 1 || remainingRounds 1);std::cout Monitoring numKeys keys per round, for a maximum of remainingRounds rounds.\n;remainingKeys numKeys;// 安装键盘输入的钩子HHOOK keyboardHook SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);// 消息循环以保持钩子活动MSG msg;while (GetMessage(msg, NULL, 0, 0)) {TranslateMessage(msg);DispatchMessage(msg);}// 卸载钩子UnhookWindowsHookEx(keyboardHook);
}// 从注册表中删除所有重映射按键
void DeleteAllRemappedKeys() {// 二次确认std::cout Are you sure you want to delete all remapped keys? This action cannot be undone. (yes/no)\n;std::string confirmation;std::cin confirmation;if (confirmation ! yes) {std::cout Action cancelled.\n;return;}// 删除注册表中的重映射按键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_SET_VALUE, hKey) ERROR_SUCCESS) {LONG result RegDeleteValue(hKey, REGISTRY_VALUE_NAME);if (result ERROR_SUCCESS || result ERROR_FILE_NOT_FOUND) {std::cout All remapped keys deleted successfully.\n;}else {std::cerr Failed to delete remapped keys.\n;}RegCloseKey(hKey);}else {std::cerr Failed to open registry key.\n;}
}void BackupScancodeMap() {// 打开注册表键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_WRITE | KEY_READ, hKey) ERROR_SUCCESS) {// 获取当前 Scancode Map 值的大小DWORD dataSize 0;DWORD dataType;if (RegQueryValueEx(hKey, REGISTRY_VALUE_NAME, NULL, dataType, NULL, dataSize) ERROR_SUCCESS dataType REG_BINARY) {// 获取当前时间作为备份文件名的一部分SYSTEMTIME sysTime;GetLocalTime(sysTime);std::wstringstream backupKeyNameStream;backupKeyNameStream BACKUP_KEY_PREFIX std::setw(4) std::setfill(L0) sysTime.wYear L_ std::setw(2) std::setfill(L0) sysTime.wMonth L_ std::setw(2) std::setfill(L0) sysTime.wDay L_ std::setw(2) std::setfill(L0) sysTime.wHour L_ std::setw(2) std::setfill(L0) sysTime.wMinute L_ std::setw(2) std::setfill(L0) sysTime.wSecond;std::wstring backupKeyName backupKeyNameStream.str();std::vectorBYTE buffer(dataSize);if (RegQueryValueEx(hKey, REGISTRY_VALUE_NAME, NULL, NULL, buffer.data(), dataSize) ERROR_SUCCESS) {// 创建新的值项来存储备份数据LONG result RegSetValueEx(hKey, backupKeyName.c_str(), 0, REG_BINARY, buffer.data(), dataSize);if (result ERROR_SUCCESS) {std::wcout LBackup of Scancode Map value successful. Backup key name: backupKeyName std::endl;// 询问用户是否删除原始键值项std::wcout LDo you want to delete the original registry key value? (Y/N): ;wchar_t response;std::wcin response;if (response LY || response Ly) {if (RegDeleteValue(hKey, REGISTRY_VALUE_NAME) ERROR_SUCCESS) {std::wcout LOriginal registry key value deleted successfully. std::endl;}else {std::wcerr LFailed to delete original registry key value. std::endl;}}else {std::wcout LOriginal registry key value not deleted. std::endl;}}else {std::cerr Failed to write Scancode Map value to backup key: result std::endl;}}else {std::cerr Failed to read registry value. std::endl;}}else {std::cerr No Scancode Map value found in the registry. std::endl;}// 关闭键RegCloseKey(hKey);}else {std::cerr Failed to open registry key. std::endl;}
}// 枚举并读取所有备份的 Scancode Map 值的键名称
void EnumerateAndPrintBackupKeys() {// 打开注册表键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_QUERY_VALUE, hKey) ERROR_SUCCESS) {// 枚举所有值项的名称DWORD index 0;WCHAR subKeyName[MAX_PATH];DWORD subKeyNameSize MAX_PATH;while (RegEnumValue(hKey, index, subKeyName, subKeyNameSize, NULL, NULL, NULL, NULL) ERROR_SUCCESS) {// 检查值项的名称的前缀如果是备份值项则输出时间信息if (wcsncmp(subKeyName, BACKUP_KEY_PREFIX, wcslen(BACKUP_KEY_PREFIX)) 0) {std::wcout LBackup time: subKeyName std::endl;}// 重置键名缓冲区大小subKeyNameSize MAX_PATH;// 移动到下一个值项index;}RegCloseKey(hKey);}else {std::cerr Failed to open registry key. std::endl;}
}// 还原指定时间的 Scancode Map 值备份
void RestoreBackupScancodeMap(const std::wstring backupTime) {// 打开注册表键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_SET_VALUE | KEY_QUERY_VALUE, hKey) ERROR_SUCCESS) {// 构造备份值项的名称std::wstring backupKeyName BACKUP_KEY_PREFIX backupTime;DWORD dataSize 0;DWORD dataType;// 获取备份值项的大小if (RegQueryValueEx(hKey, backupKeyName.c_str(), NULL, dataType, NULL, dataSize) ERROR_SUCCESS dataType REG_BINARY) {// 读取备份值项std::vectorBYTE buffer(dataSize);if (RegQueryValueEx(hKey, backupKeyName.c_str(), NULL, NULL, buffer.data(), dataSize) ERROR_SUCCESS) {// 将备份值项的数据写入 Scancode Mapif (RegSetValueEx(hKey, REGISTRY_VALUE_NAME, 0, REG_BINARY, buffer.data(), dataSize) ERROR_SUCCESS) {std::wcout LRestored Scancode Map from backup created at: backupTime std::endl;}else {std::cerr Failed to restore Scancode Map from backup. std::endl;}}}else {std::cerr Backup key not found or not a valid REG_BINARY value. std::endl;}RegCloseKey(hKey);}else {std::cerr Failed to open registry key. std::endl;}
}// 更新重映射信息到注册表
bool UpdateRemapInfo(const std::vectorstd::pairWORD, WORD remapInfo) {std::vectorBYTE buffer(20 remapInfo.size() * 4, 0);*(DWORD*)(buffer.data() 8) remapInfo.size() 1;for (size_t i 0; i remapInfo.size(); i) {*(WORD*)(buffer.data() 12 i * 4) remapInfo[i].second;*(WORD*)(buffer.data() 14 i * 4) remapInfo[i].first;}HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_SET_VALUE, hKey) ERROR_SUCCESS) {if (RegSetValueEx(hKey, REGISTRY_VALUE_NAME, 0, REG_BINARY, buffer.data(), buffer.size()) ERROR_SUCCESS) {RegCloseKey(hKey);return true;}RegCloseKey(hKey);}return false;
}// 删除重映射信息中的指定项
void DeleteRemapItemByIndex(std::vectorstd::pairWORD, WORD remapInfo) {// 枚举原有数据EnumerateRemappedKeys(remapInfo);std::cout Enter the numbers of items you want to delete (e.g., 1 2 3), separated by spaces: ;std::string input;std::getline(std::cin, input);std::istringstream iss(input);std::vectorint deleteIndices;int index;while (iss index) {deleteIndices.push_back(index - 1); // 索引从1开始转换为从0开始}std::vectorstd::pairWORD, WORD updatedRemapInfo;for (size_t i 0; i remapInfo.size(); i) {if (std::find(deleteIndices.begin(), deleteIndices.end(), i) deleteIndices.end()) {updatedRemapInfo.push_back(remapInfo[i]);}}if (UpdateRemapInfo(updatedRemapInfo)) {std::cout Remapped items deleted successfully.\n;}else {std::cerr Failed to delete remapped items.\n;}
}// 添加重映射按键
void AddRemapItemByIndex(std::vectorstd::pairWORD, WORD remapInfo,std::pairWORD, WORD NewMapNode, size_t dwIdToInsert) {// 参数范围校验if (dwIdToInsert 1 || dwIdToInsert remapInfo.size() ){std::cerr Error invalid parameters.\n;return;}// 检查是否有重复的映射for (const auto pair : remapInfo) {if (pair.first NewMapNode.first || pair.second NewMapNode.second) {std::cerr Error Duplicate remapped item.\n;return;}}// 向 remapInfo 中索引为 dwIdToInsert 前面插入元素 NewMapNode// 索引为 dwIdToInsert-1 后面插入等同于在索引为 dwIdToInsert 前插入 auto it remapInfo.begin() dwIdToInsert;remapInfo.insert(it, NewMapNode);// 利用新的结构信息更新注册表if (UpdateRemapInfo(remapInfo)) {std::cout Remapped items add successfully.\n;}else {std::cerr Failed to insert remapped items.\n;}
}// 禁用 Remap 注册表项
void ChangeScancodeMapStatus(BOOL bEnable) {// 打开注册表键HKEY hKey;if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_KEY, 0, KEY_WRITE | KEY_READ, hKey) ERROR_SUCCESS) {// 获取当前 Scancode Map 值的大小DWORD dataSize 0;DWORD dataType;// 构造新的名称std::wstringstream disabledKeyNameStream;std::wstringstream checkKeyNameStream;disabledKeyNameStream REGISTRY_VALUE_NAME (bEnable ? L : DESABLED_KEY_PREFIX);std::wstring disabledKeyName disabledKeyNameStream.str();checkKeyNameStream REGISTRY_VALUE_NAME (bEnable ? DESABLED_KEY_PREFIX : L);std::wstring checkKeyName checkKeyNameStream.str();if (RegQueryValueEx(hKey, checkKeyName.c_str(), NULL, dataType, NULL, dataSize) ERROR_SUCCESS dataType REG_BINARY) {std::vectorBYTE buffer(dataSize);if (RegQueryValueEx(hKey, checkKeyName.c_str(), NULL, NULL, buffer.data(), dataSize) ERROR_SUCCESS) {// 创建新的值项来存储备份数据LONG result RegSetValueEx(hKey, disabledKeyName.c_str(), 0, REG_BINARY, buffer.data(), dataSize);if (result ERROR_SUCCESS) {std::wcout (bEnable ? LEnable : LDisable) L Scancode Map value successful. New key name: disabledKeyName std::endl;// 删除原始键值项if (RegDeleteValue(hKey, checkKeyName.c_str()) ERROR_SUCCESS) {std::wcout LOriginal registry key value deleted successfully. std::endl;}else {std::wcerr LFailed to delete original registry key value. std::endl;RegDeleteValue(hKey, disabledKeyName.c_str());}}else {std::cerr Failed to write Scancode Map value to disabled key: result std::endl;}}else {std::cerr Failed to read registry value. std::endl;}}else {if (RegQueryValueEx(hKey, disabledKeyName.c_str(), NULL, dataType, NULL, dataSize) ERROR_SUCCESS dataType REG_BINARY) {std::wcout LRemapping keys were already (bEnable ? Lenabled : Ldisabled) L earlier. std::endl;}else {std::cerr No Scancode Map value found in the registry. std::endl;}}// 关闭键RegCloseKey(hKey);}else {std::cerr Failed to open registry key. std::endl;}
}// 将 char* 类型的字符串转换为 std::wstring
std::wstring ConvertToWideString(const char* str) {int size MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);if (size 0) {// 转换失败return L;}std::wstring result(size, L\0);MultiByteToWideChar(CP_UTF8, 0, str, -1, result[0], size);return result;
}int main(int argc, char* argv[]) {if (argc 2) {std::cerr Usage: argv[0] option [configFile]\n;return 1;}std::string option argv[1];if (option /enumerate) { // 解析目前注册表中重映射键值的数据std::vectorstd::pairWORD, WORD remapInfo;if (ParseRemapInfo(remapInfo)) {EnumerateRemappedKeys(remapInfo);}else {std::cerr Failed to parse remap info.\n;}}else if (option /setremap) { // 向注册表中覆盖写入重映射键值的数据if (argc ! 3) {std::cerr Usage: argv[0] /setremap configFilePath\n;return 1;}std::string configFile argv[2];ModifyRemappedKeys(configFile);}else if (option /queryActiveKey) { // 动态查询按键的扫描码QueryScanCodeForKey();}else if (option /deleteAllMap) // 删除所有重映射键数据{DeleteAllRemappedKeys();}else if (option /modifyDelKey) { // 删除指定的重映射键数据std::vectorstd::pairWORD, WORD remapInfo;if (ParseRemapInfo(remapInfo)) {DeleteRemapItemByIndex(remapInfo);}else {std::cerr Failed to parse remap info.\n;}}else if (option /modifyInsertKey) // 在指定的元素后面添加新的按键映射{std::vectorstd::pairWORD, WORD remapInfo;WORD oldScanCode 0, newScanCode 0;size_t index 0;if (ParseRemapInfo(remapInfo)) { // 解析注册表参数// 枚举原有数据EnumerateRemappedKeys(remapInfo);// 选择插入的位置和数据std::cout Enter the Original Key scan code: ;std::cin std::hex oldScanCode;std::cout Enter the Key scan code you wannt to replace to: ;std::cin std::hex newScanCode;std::cout Enter the number of item you wannt to insert after: ;std::cin index;// 调整字节顺序oldScanCode ((oldScanCode 0xFF00) 8) | ((oldScanCode 0x00FF) 8);newScanCode ((newScanCode 0xFF00) 8) | ((newScanCode 0x00FF) 8);// 写入数据AddRemapItemByIndex(remapInfo,std::make_pair(oldScanCode, newScanCode), index);}else {std::cerr Failed to parse remap info.\n;}}else if (option /modifyAddKey) // 在映射表的末尾追加按键映射{std::vectorstd::pairWORD, WORD remapInfo;WORD oldScanCode 0, newScanCode 0;size_t index 0;if (ParseRemapInfo(remapInfo)) { // 解析注册表参数// 选择插入的位置和数据std::cout Enter the Original Key scan code: ;std::cin std::hex oldScanCode;std::cout Enter the Key scan code you wannt to replace to: ;std::cin std::hex newScanCode;index remapInfo.size(); // 在结尾插入// 调整字节顺序oldScanCode ((oldScanCode 0xFF00) 8) | ((oldScanCode 0x00FF) 8);newScanCode ((newScanCode 0xFF00) 8) | ((newScanCode 0x00FF) 8);// 写入数据AddRemapItemByIndex(remapInfo,std::make_pair(oldScanCode, newScanCode), index);}else {std::cerr Failed to parse remap info.\n;}}else if (option /statusMap) // 启用或者禁用重映射键可恢复1表示启用0表示禁用{if (argc ! 3) {std::cerr Usage: argv[0] /statusMap bEnable\n;return 1;}if (std::string(argv[2]) 1){std::cout Try to enable ReMap Key.\n;ChangeScancodeMapStatus(TRUE);}else if (std::string(argv[2]) 0){std::cout Try to disable ReMap Key.\n;ChangeScancodeMapStatus(FALSE);}}else if (option /makebackup) { // 备份当前注册表重映射键数据BackupScancodeMap();}else if (option /recoverMap) { // 按照备份日期还原数据if (argc ! 3) {std::cerr Usage: argv[0] /recoverMap backupTime\n;return 1;}std::wstring backupTime ConvertToWideString(argv[2]);if (backupTime L)return 1;RestoreBackupScancodeMap(backupTime);}else if (option /readbackup) { // 读取备份文件列表EnumerateAndPrintBackupKeys();}else {std::cerr Invalid option.\n;return 1;}return 0;
}程序需要管理员权限设置清单文件即可 标题 测试截图如下 标题 3.2 C# 实现的窗口工具
Medo 制作的开源工具 Scancode Map 是一个不错的选择它具有完备的查询、修改、删除等功能我的程序一定程度上参考了他的思路。
这是该工具的界面视图 Scancode Map 截图 1 Scancode Map 截图 2 原文链接为Scancode Map 1.11 – Medos Home Page。
网盘下载链接https://pan.baidu.com/s/1Dxn8R3GEdol59ObYAMTLHw?pwdvtq3
提取码vtq3 里面有我重新编译好的文件在 /source/bin 内并且包含我写的控制台程序
官网程序下载链接https://www.medo64.com/download/scancodemap111.exe。
源代码 Github 链接Release Most recent build · medo64/ScancodeMap · GitHub。
四、总结
本文简单介绍了使用 Scancode Map 键盘扫描码映射表禁用 CtrlAltDel 键的方法。浅谈了该方法的利弊。修改注册表屏蔽该按键的方法还有另外一个稳定的方法就是利用 Disable 项隐藏相应的选项这个方法也是以前讨论最多的方法比按键扫描码用的还广泛还有一个就是进程冻结法。但是都有缺点比如可以注册表方法是可以轻易恢复的进程冻结存在不稳定性冻结后容易让进程陷入 RPC 死锁导致无法恢复。 【保留备用】
本文属于原创文章转载请注明出处
https://blog.csdn.net/qq_59075481/article/details/136104444。
发布于2024.02.13更新于2024.02.13.