From abd22ab7f11068e363896a995e1b1ae907e3b087 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Mon, 25 Nov 2024 17:15:22 +0800 Subject: [PATCH] [fix] fix Win/MacOSX keycodes convertion --- .../keyboard/mac/keyboard_capturer.cpp | 200 +++++++++----- .../keyboard/mac/keyboard_capturer.h | 11 + .../keyboard/mac/keyboard_converter.h | 254 ++++++++++++++++++ src/single_window/control_bar.cpp | 15 +- 4 files changed, 404 insertions(+), 76 deletions(-) create mode 100644 src/device_controller/keyboard/mac/keyboard_converter.h diff --git a/src/device_controller/keyboard/mac/keyboard_capturer.cpp b/src/device_controller/keyboard/mac/keyboard_capturer.cpp index 3efff67..36d40d2 100644 --- a/src/device_controller/keyboard/mac/keyboard_capturer.cpp +++ b/src/device_controller/keyboard/mac/keyboard_capturer.cpp @@ -1,97 +1,157 @@ #include "keyboard_capturer.h" -#include - -#include - +#include "keyboard_converter.h" #include "rd_log.h" -// vkCode 到 CGKeyCode 的映射表 -std::unordered_map vkCodeToCGKeyCode = { - // 字母键 - {0x41, 0x00}, // A - {0x42, 0x0B}, // B - {0x43, 0x08}, // C - {0x44, 0x02}, // D - {0x45, 0x0E}, // E - {0x46, 0x03}, // F - {0x47, 0x05}, // G - {0x48, 0x04}, // H - {0x49, 0x22}, // I - {0x4A, 0x26}, // J - {0x4B, 0x28}, // K - {0x4C, 0x25}, // L - {0x4D, 0x2E}, // M - {0x4E, 0x2D}, // N - {0x4F, 0x1F}, // O - {0x50, 0x23}, // P - {0x51, 0x0C}, // Q - {0x52, 0x0F}, // R - {0x53, 0x01}, // S - {0x54, 0x11}, // T - {0x55, 0x20}, // U - {0x56, 0x09}, // V - {0x57, 0x0D}, // W - {0x58, 0x07}, // X - {0x59, 0x10}, // Y - {0x5A, 0x06}, // Z +static OnKeyAction g_on_key_action = nullptr; +static void *g_user_ptr = nullptr; - // 数字键 - {0x30, 0x1D}, // 0 - {0x31, 0x12}, // 1 - {0x32, 0x13}, // 2 - {0x33, 0x14}, // 3 - {0x34, 0x15}, // 4 - {0x35, 0x17}, // 5 - {0x36, 0x16}, // 6 - {0x37, 0x1A}, // 7 - {0x38, 0x1C}, // 8 - {0x39, 0x19}, // 9 +CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, + CGEventRef event, void *userInfo) { + KeyboardCapturer *keyboard_capturer = (KeyboardCapturer *)userInfo; + if (!keyboard_capturer) { + LOG_ERROR("keyboard_capturer is nullptr"); + return event; + } - // 功能键 - {0x20, 0x31}, // 空格 - {0x0D, 0x24}, // 回车 - {0x08, 0x33}, // 退格 - {0x1B, 0x35}, // Esc - {0x2E, 0x75}, // Delete + int vk_code = 0; - // 箭头键 - {0x25, 0x7B}, // 左 - {0x27, 0x7C}, // 右 - {0x26, 0x7E}, // 上 - {0x28, 0x7D}, // 下 + if (type == kCGEventKeyDown || type == kCGEventKeyUp) { + CGKeyCode key_code = static_cast( + CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)); + std::cout << "Key Down Event: key code = " << key_code << std::endl; + if (CGKeyCodeToVkCode.find(key_code) != CGKeyCodeToVkCode.end()) { + g_on_key_action(CGKeyCodeToVkCode[key_code], type == kCGEventKeyDown, + g_user_ptr); + } else { + LOG_ERROR("key_code not found"); + } + } else if (type == kCGEventFlagsChanged) { + CGEventFlags current_flags = CGEventGetFlags(event); + CGKeyCode key_code = static_cast( + CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)); + // 检测 CapsLock 键 + bool caps_lock_state = (current_flags & kCGEventFlagMaskAlphaShift) != 0; + if (caps_lock_state != keyboard_capturer->caps_lock_flag_) { + keyboard_capturer->caps_lock_flag_ = caps_lock_state; + if (keyboard_capturer->caps_lock_flag_) { + std::cout << "CapsLock Pressed" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr); + } else { + std::cout << "CapsLock Released" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr); + } + } - // 功能键 F1-F12 - {0x70, 0x7A}, // F1 - {0x71, 0x78}, // F2 - {0x72, 0x63}, // F3 - {0x73, 0x76}, // F4 - {0x74, 0x60}, // F5 - {0x75, 0x61}, // F6 - {0x76, 0x62}, // F7 - {0x77, 0x64}, // F8 - {0x78, 0x65}, // F9 - {0x79, 0x6D}, // F10 - {0x7A, 0x67}, // F11 - {0x7B, 0x6F}, // F12 -}; + // 检测 Shift 键 + bool shift_state = (current_flags & kCGEventFlagMaskShift) != 0; + if (shift_state != keyboard_capturer->shift_flag_) { + keyboard_capturer->shift_flag_ = shift_state; + if (keyboard_capturer->shift_flag_) { + LOG_INFO("Shift Pressed: key_code = {:#04x} -> {:#04x}", key_code, + CGKeyCodeToVkCode[key_code]); + g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr); + } else { + LOG_INFO("Shift Released: key_code = {:#04x} -> {:#04x}", key_code, + CGKeyCodeToVkCode[key_code]); + g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr); + } + } + + // 检测 Control 键 + bool control_state = (current_flags & kCGEventFlagMaskControl) != 0; + if (control_state != keyboard_capturer->control_flag_) { + keyboard_capturer->control_flag_ = control_state; + if (keyboard_capturer->control_flag_) { + std::cout << "Control Pressed" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr); + } else { + std::cout << "Control Released" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr); + } + } + + // 检测 Option 键 + bool option_state = (current_flags & kCGEventFlagMaskAlternate) != 0; + if (option_state != keyboard_capturer->option_flag_) { + keyboard_capturer->option_flag_ = option_state; + if (keyboard_capturer->option_flag_) { + std::cout << "Option Pressed" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr); + } else { + std::cout << "Option Released" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr); + } + } + + // 检测 Command 键 + bool command_state = (current_flags & kCGEventFlagMaskCommand) != 0; + if (command_state != keyboard_capturer->command_flag_) { + keyboard_capturer->command_flag_ = command_state; + if (keyboard_capturer->command_flag_) { + std::cout << "Command Pressed" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr); + } else { + std::cout << "Command Released" << std::endl; + g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr); + } + } + } + + return nullptr; // 返回 null 表示阻止事件 +} KeyboardCapturer::KeyboardCapturer() {} KeyboardCapturer::~KeyboardCapturer() {} int KeyboardCapturer::Hook(OnKeyAction on_key_action, void *user_ptr) { + g_on_key_action = on_key_action; + g_user_ptr = user_ptr; + + CGEventMask eventMask = (1 << kCGEventKeyDown) | (1 << kCGEventKeyUp) | + (1 << kCGEventFlagsChanged); + + eventTap = CGEventTapCreate(kCGSessionEventTap, // 事件 Tap 的作用范围 + kCGHeadInsertEventTap, // 插入到事件队列的最前面 + kCGEventTapOptionDefault, // 默认选项 + eventMask, // 要拦截的事件类型 + eventCallback, // 事件回调函数 + this // 用户数据指针(可选) + ); + + if (!eventTap) { + std::cerr << "Failed to create event tap. Ensure Accessibility permissions " + "are granted." + << std::endl; + return -1; + } + + runLoopSource = + CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); + + CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, + kCFRunLoopCommonModes); + + CGEventTapEnable(eventTap, true); return 0; } -int KeyboardCapturer::Unhook() { return 0; } +int KeyboardCapturer::Unhook() { + CFRelease(runLoopSource); + CFRelease(eventTap); + return 0; +} int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) { + LOG_INFO("SendKeyboardCommand: key_code = {:#04x}", key_code); if (vkCodeToCGKeyCode.find(key_code) != vkCodeToCGKeyCode.end()) { CGKeyCode cg_key_code = vkCodeToCGKeyCode[key_code]; CGEventRef event = CGEventCreateKeyboardEvent(NULL, cg_key_code, is_down); CGEventPost(kCGHIDEventTap, event); CFRelease(event); + } else { + LOG_ERROR("key_code not found"); } return 0; diff --git a/src/device_controller/keyboard/mac/keyboard_capturer.h b/src/device_controller/keyboard/mac/keyboard_capturer.h index 0bec57b..e74d78d 100644 --- a/src/device_controller/keyboard/mac/keyboard_capturer.h +++ b/src/device_controller/keyboard/mac/keyboard_capturer.h @@ -7,6 +7,8 @@ #ifndef _KEYBOARD_CAPTURER_H_ #define _KEYBOARD_CAPTURER_H_ +#include + #include "device_controller.h" class KeyboardCapturer : public DeviceController { @@ -20,6 +22,15 @@ class KeyboardCapturer : public DeviceController { virtual int SendKeyboardCommand(int key_code, bool is_down); private: + CFMachPortRef eventTap; + CFRunLoopSourceRef runLoopSource; + + public: + bool caps_lock_flag_ = false; + bool shift_flag_ = false; + bool control_flag_ = false; + bool option_flag_ = false; + bool command_flag_ = false; }; #endif \ No newline at end of file diff --git a/src/device_controller/keyboard/mac/keyboard_converter.h b/src/device_controller/keyboard/mac/keyboard_converter.h new file mode 100644 index 0000000..47db94e --- /dev/null +++ b/src/device_controller/keyboard/mac/keyboard_converter.h @@ -0,0 +1,254 @@ +/* + * @Author: DI JUNKUN + * @Date: 2024-11-25 + * Copyright (c) 2024 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _KEYBOARD_CONVERTER_H_ +#define _KEYBOARD_CONVERTER_H_ + +#include + +// Windows vkCode 转 macOS CGKeyCode 映射表 (104 键) +std::map vkCodeToCGKeyCode = { + // 字母键 (A-Z) + {0x41, 0x00}, // A + {0x42, 0x0B}, // B + {0x43, 0x08}, // C + {0x44, 0x02}, // D + {0x45, 0x0E}, // E + {0x46, 0x03}, // F + {0x47, 0x05}, // G + {0x48, 0x04}, // H + {0x49, 0x22}, // I + {0x4A, 0x26}, // J + {0x4B, 0x28}, // K + {0x4C, 0x25}, // L + {0x4D, 0x2E}, // M + {0x4E, 0x2D}, // N + {0x4F, 0x1F}, // O + {0x50, 0x23}, // P + {0x51, 0x0C}, // Q + {0x52, 0x0F}, // R + {0x53, 0x01}, // S + {0x54, 0x11}, // T + {0x55, 0x20}, // U + {0x56, 0x09}, // V + {0x57, 0x0D}, // W + {0x58, 0x07}, // X + {0x59, 0x10}, // Y + {0x5A, 0x06}, // Z + + // 数字键 (0-9) + {0x30, 0x1D}, // 0 + {0x31, 0x12}, // 1 + {0x32, 0x13}, // 2 + {0x33, 0x14}, // 3 + {0x34, 0x15}, // 4 + {0x35, 0x17}, // 5 + {0x36, 0x16}, // 6 + {0x37, 0x1A}, // 7 + {0x38, 0x1C}, // 8 + {0x39, 0x19}, // 9 + + // 功能键 (F1-F12) + {0x70, 0x7A}, // F1 + {0x71, 0x78}, // F2 + {0x72, 0x63}, // F3 + {0x73, 0x76}, // F4 + {0x74, 0x60}, // F5 + {0x75, 0x61}, // F6 + {0x76, 0x62}, // F7 + {0x77, 0x64}, // F8 + {0x78, 0x65}, // F9 + {0x79, 0x6D}, // F10 + {0x7A, 0x67}, // F11 + {0x7B, 0x6F}, // F12 + + // 控制键 + {0x1B, 0x35}, // Escape + {0x0D, 0x24}, // Enter + {0x20, 0x31}, // Space + {0x08, 0x33}, // Backspace + {0x09, 0x30}, // Tab + {0x2C, 0x74}, // Print Screen + {0x2D, 0x72}, // Insert + {0x2E, 0x75}, // Delete + {0x24, 0x73}, // Home + {0x23, 0x77}, // End + {0x21, 0x79}, // Page Up + {0x22, 0x7A}, // Page Down + + // 箭头键 + {0x25, 0x7B}, // Left Arrow + {0x27, 0x7C}, // Right Arrow + {0x26, 0x7E}, // Up Arrow + {0x28, 0x7D}, // Down Arrow + + // 数字小键盘 (Numpad) + {0x60, 0x52}, // Numpad 0 + {0x61, 0x53}, // Numpad 1 + {0x62, 0x54}, // Numpad 2 + {0x63, 0x55}, // Numpad 3 + {0x64, 0x56}, // Numpad 4 + {0x65, 0x57}, // Numpad 5 + {0x66, 0x58}, // Numpad 6 + {0x67, 0x59}, // Numpad 7 + {0x68, 0x5B}, // Numpad 8 + {0x69, 0x5C}, // Numpad 9 + {0x6E, 0x41}, // Numpad . + {0x6F, 0x4B}, // Numpad / + {0x6A, 0x43}, // Numpad * + {0x6D, 0x4E}, // Numpad - + {0x6B, 0x45}, // Numpad + + + // 符号键 + {0xBA, 0x29}, // ; (Semicolon) + {0xDE, 0x27}, // ' (Quote) + {0xC0, 0x32}, // ` (Backtick) + {0xBC, 0x2B}, // , (Comma) + {0xBE, 0x2F}, // . (Period) + {0xBF, 0x2C}, // / (Slash) + {0xDC, 0x2A}, // \ (Backslash) + {0xDB, 0x21}, // [ (Left Bracket) + {0xDD, 0x1E}, // ] (Right Bracket) + {0xBD, 0x1B}, // - (Minus) + {0xBB, 0x18}, // = (Equals) + + // 修饰键 + {0x14, 0x39}, // Caps Lock + {0xA0, 0x38}, // Shift (Left) + {0xA2, 0x3B}, // Shift (Right) + {0xA3, 0x3B}, // Ctrl (Left) + {0xA3, 0x3E}, // Ctrl (Right) + {0xA4, 0x3A}, // Alt (Left) + {0xA5, 0x3D}, // Alt (Right) + {0x5B, 0x37}, // Left Command (Windows key) + {0x5C, 0x36}, // Right Command +}; + +// macOS CGKeyCode 转 Windows vkCode 映射表 +std::map CGKeyCodeToVkCode = { + // 字母键 (A-Z) + {0x00, 0x41}, // A + {0x0B, 0x42}, // B + {0x08, 0x43}, // C + {0x02, 0x44}, // D + {0x0E, 0x45}, // E + {0x03, 0x46}, // F + {0x05, 0x47}, // G + {0x04, 0x48}, // H + {0x22, 0x49}, // I + {0x26, 0x4A}, // J + {0x28, 0x4B}, // K + {0x25, 0x4C}, // L + {0x2E, 0x4D}, // M + {0x2D, 0x4E}, // N + {0x1F, 0x4F}, // O + {0x23, 0x50}, // P + {0x0C, 0x51}, // Q + {0x0F, 0x52}, // R + {0x01, 0x53}, // S + {0x11, 0x54}, // T + {0x20, 0x55}, // U + {0x09, 0x56}, // V + {0x0D, 0x57}, // W + {0x07, 0x58}, // X + {0x10, 0x59}, // Y + {0x06, 0x5A}, // Z + + // 数字键 (0-9) + {0x1D, 0x30}, // 0 + {0x12, 0x31}, // 1 + {0x13, 0x32}, // 2 + {0x14, 0x33}, // 3 + {0x15, 0x34}, // 4 + {0x17, 0x35}, // 5 + {0x16, 0x36}, // 6 + {0x1A, 0x37}, // 7 + {0x1C, 0x38}, // 8 + {0x19, 0x39}, // 9 + + // 功能键 (F1-F12) + {0x7A, 0x70}, // F1 + {0x78, 0x71}, // F2 + {0x63, 0x72}, // F3 + {0x76, 0x73}, // F4 + {0x60, 0x74}, // F5 + {0x61, 0x75}, // F6 + {0x62, 0x76}, // F7 + {0x64, 0x77}, // F8 + {0x65, 0x78}, // F9 + {0x6D, 0x79}, // F10 + {0x67, 0x7A}, // F11 + {0x6F, 0x7B}, // F12 + + // 控制键 + {0x35, 0x1B}, // Escape + {0x24, 0x0D}, // Enter + {0x31, 0x20}, // Space + {0x33, 0x08}, // Backspace + {0x30, 0x09}, // Tab + {0x74, 0x2C}, // Print Screen + {0x72, 0x2D}, // Insert + {0x75, 0x2E}, // Delete + {0x73, 0x24}, // Home + {0x77, 0x23}, // End + {0x79, 0x21}, // Page Up + {0x7A, 0x22}, // Page Down + + // 箭头键 + {0x7B, 0x25}, // Left Arrow + {0x7C, 0x27}, // Right Arrow + {0x7E, 0x26}, // Up Arrow + {0x7D, 0x28}, // Down Arrow + + // 数字小键盘 (Numpad) + {0x52, 0x60}, // Numpad 0 + {0x53, 0x61}, // Numpad 1 + {0x54, 0x62}, // Numpad 2 + {0x55, 0x63}, // Numpad 3 + {0x56, 0x64}, // Numpad 4 + {0x57, 0x65}, // Numpad 5 + {0x58, 0x66}, // Numpad 6 + {0x59, 0x67}, // Numpad 7 + {0x5B, 0x68}, // Numpad 8 + {0x5C, 0x69}, // Numpad 9 + {0x41, 0x6E}, // Numpad . + {0x4B, 0x6F}, // Numpad / + {0x43, 0x6A}, // Numpad * + {0x4E, 0x6D}, // Numpad - + {0x45, 0x6B}, // Numpad + + + // 符号键 + {0x29, 0xBA}, // ; (Semicolon) + {0x27, 0xDE}, // ' (Quote) + {0x32, 0xC0}, // ` (Backtick) + {0x2B, 0xBC}, // , (Comma) + {0x2F, 0xBE}, // . (Period) + {0x2C, 0xBF}, // / (Slash) + {0x2A, 0xDC}, // \ (Backslash) + {0x21, 0xDB}, // [ (Left Bracket) + {0x1E, 0xDD}, // ] (Right Bracket) + {0x1B, 0xBD}, // - (Minus) + {0x18, 0xBB}, // = (Equals) + + // 修饰键 + {0x39, 0x14}, // Caps Lock + {0x38, 0xA0}, // Shift (Left) + {0x3C, 0xA1}, // Shift (Right) + {0x3B, 0xA2}, // Control (Left) + {0x3E, 0xA3}, // Control (Right) + {0x3A, 0xA4}, // Alt (Left) + {0x3D, 0xA5}, // Alt (Right) + {0x37, 0x5B}, // Left Command (Windows key) + {0x36, 0x5C}, // Right Command +}; + +#define MAC_CAPSLOCK 0x39 +#define MAC_SHIFT 0x38 +#define MAC_CONTROL 0x3B +#define MAC_OPTION 0x3A +#define MAC_COMMAND 0x37 + +#endif \ No newline at end of file diff --git a/src/single_window/control_bar.cpp b/src/single_window/control_bar.cpp index 66cbca6..5f7a501 100644 --- a/src/single_window/control_bar.cpp +++ b/src/single_window/control_bar.cpp @@ -210,13 +210,14 @@ int Render::NetTrafficStats(ImVec2 mouse_button_pos) { ImGui::TableNextColumn(); ImGui::Text(" "); ImGui::TableNextColumn(); - ImGui::Text(localization::in[localization_language_index_].c_str()); + ImGui::Text("%s", localization::in[localization_language_index_].c_str()); ImGui::TableNextColumn(); - ImGui::Text(localization::out[localization_language_index_].c_str()); + ImGui::Text("%s", localization::out[localization_language_index_].c_str()); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(localization::video[localization_language_index_].c_str()); + ImGui::Text("%s", + localization::video[localization_language_index_].c_str()); ImGui::TableNextColumn(); BitrateDisplay(net_traffic_stats_.video_in); ImGui::TableNextColumn(); @@ -224,7 +225,8 @@ int Render::NetTrafficStats(ImVec2 mouse_button_pos) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(localization::audio[localization_language_index_].c_str()); + ImGui::Text("%s", + localization::audio[localization_language_index_].c_str()); ImGui::TableNextColumn(); BitrateDisplay(net_traffic_stats_.audio_in); ImGui::TableNextColumn(); @@ -232,7 +234,7 @@ int Render::NetTrafficStats(ImVec2 mouse_button_pos) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(localization::data[localization_language_index_].c_str()); + ImGui::Text("%s", localization::data[localization_language_index_].c_str()); ImGui::TableNextColumn(); BitrateDisplay(net_traffic_stats_.data_in); ImGui::TableNextColumn(); @@ -240,7 +242,8 @@ int Render::NetTrafficStats(ImVec2 mouse_button_pos) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text(localization::total[localization_language_index_].c_str()); + ImGui::Text("%s", + localization::total[localization_language_index_].c_str()); ImGui::TableNextColumn(); BitrateDisplay(net_traffic_stats_.total_in); ImGui::TableNextColumn();