mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-03-26 19:27:30 +08:00
[fix] fix mac-to-windows symbol key input
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
#include "keyboard_capturer.h"
|
#include "keyboard_capturer.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "keyboard_converter.h"
|
#include "keyboard_converter.h"
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
|
|
||||||
@@ -7,6 +9,96 @@ namespace crossdesk {
|
|||||||
|
|
||||||
static OnKeyAction g_on_key_action = nullptr;
|
static OnKeyAction g_on_key_action = nullptr;
|
||||||
static void* g_user_ptr = nullptr;
|
static void* g_user_ptr = nullptr;
|
||||||
|
static std::unordered_map<int, int> g_unmapped_keycode_to_vk;
|
||||||
|
|
||||||
|
static int VkCodeFromUnicode(UniChar ch) {
|
||||||
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
|
return static_cast<int>(ch - 'a' + 'A');
|
||||||
|
}
|
||||||
|
if (ch >= 'A' && ch <= 'Z') {
|
||||||
|
return static_cast<int>(ch);
|
||||||
|
}
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
return static_cast<int>(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case ' ':
|
||||||
|
return 0x20; // VK_SPACE
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
return 0xBD; // VK_OEM_MINUS
|
||||||
|
case '=':
|
||||||
|
case '+':
|
||||||
|
return 0xBB; // VK_OEM_PLUS
|
||||||
|
case '[':
|
||||||
|
case '{':
|
||||||
|
return 0xDB; // VK_OEM_4
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
return 0xDD; // VK_OEM_6
|
||||||
|
case '\\':
|
||||||
|
case '|':
|
||||||
|
return 0xDC; // VK_OEM_5
|
||||||
|
case ';':
|
||||||
|
case ':':
|
||||||
|
return 0xBA; // VK_OEM_1
|
||||||
|
case '\'':
|
||||||
|
case '"':
|
||||||
|
return 0xDE; // VK_OEM_7
|
||||||
|
case ',':
|
||||||
|
case '<':
|
||||||
|
return 0xBC; // VK_OEM_COMMA
|
||||||
|
case '.':
|
||||||
|
case '>':
|
||||||
|
return 0xBE; // VK_OEM_PERIOD
|
||||||
|
case '/':
|
||||||
|
case '?':
|
||||||
|
return 0xBF; // VK_OEM_2
|
||||||
|
case '`':
|
||||||
|
case '~':
|
||||||
|
return 0xC0; // VK_OEM_3
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ResolveVkCodeFromMacEvent(CGEventRef event, CGKeyCode key_code,
|
||||||
|
bool is_key_down) {
|
||||||
|
auto key_it = CGKeyCodeToVkCode.find(key_code);
|
||||||
|
if (key_it != CGKeyCodeToVkCode.end()) {
|
||||||
|
if (is_key_down) {
|
||||||
|
g_unmapped_keycode_to_vk.erase(static_cast<int>(key_code));
|
||||||
|
}
|
||||||
|
return key_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vk_code = -1;
|
||||||
|
UniChar chars[4] = {0};
|
||||||
|
UniCharCount char_count = 0;
|
||||||
|
CGEventKeyboardGetUnicodeString(event, 4, &char_count, chars);
|
||||||
|
if (char_count > 0) {
|
||||||
|
vk_code = VkCodeFromUnicode(chars[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vk_code < 0) {
|
||||||
|
auto fallback_it =
|
||||||
|
g_unmapped_keycode_to_vk.find(static_cast<int>(key_code));
|
||||||
|
if (fallback_it != g_unmapped_keycode_to_vk.end()) {
|
||||||
|
vk_code = fallback_it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vk_code >= 0) {
|
||||||
|
if (is_key_down) {
|
||||||
|
g_unmapped_keycode_to_vk[static_cast<int>(key_code)] = vk_code;
|
||||||
|
} else {
|
||||||
|
g_unmapped_keycode_to_vk.erase(static_cast<int>(key_code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vk_code;
|
||||||
|
}
|
||||||
|
|
||||||
CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type,
|
CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type,
|
||||||
CGEventRef event, void* userInfo) {
|
CGEventRef event, void* userInfo) {
|
||||||
@@ -22,11 +114,12 @@ CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == kCGEventKeyDown || type == kCGEventKeyUp) {
|
if (type == kCGEventKeyDown || type == kCGEventKeyUp) {
|
||||||
|
const bool is_key_down = (type == kCGEventKeyDown);
|
||||||
CGKeyCode key_code = static_cast<CGKeyCode>(
|
CGKeyCode key_code = static_cast<CGKeyCode>(
|
||||||
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
|
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
|
||||||
auto key_it = CGKeyCodeToVkCode.find(key_code);
|
int vk_code = ResolveVkCodeFromMacEvent(event, key_code, is_key_down);
|
||||||
if (key_it != CGKeyCodeToVkCode.end()) {
|
if (vk_code >= 0) {
|
||||||
g_on_key_action(key_it->second, type == kCGEventKeyDown, g_user_ptr);
|
g_on_key_action(vk_code, is_key_down, g_user_ptr);
|
||||||
}
|
}
|
||||||
} else if (type == kCGEventFlagsChanged) {
|
} else if (type == kCGEventFlagsChanged) {
|
||||||
CGEventFlags current_flags = CGEventGetFlags(event);
|
CGEventFlags current_flags = CGEventGetFlags(event);
|
||||||
@@ -87,6 +180,7 @@ int KeyboardCapturer::Hook(OnKeyAction on_key_action, void* user_ptr) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_unmapped_keycode_to_vk.clear();
|
||||||
g_on_key_action = on_key_action;
|
g_on_key_action = on_key_action;
|
||||||
g_user_ptr = user_ptr;
|
g_user_ptr = user_ptr;
|
||||||
|
|
||||||
@@ -127,6 +221,7 @@ int KeyboardCapturer::Hook(OnKeyAction on_key_action, void* user_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int KeyboardCapturer::Unhook() {
|
int KeyboardCapturer::Unhook() {
|
||||||
|
g_unmapped_keycode_to_vk.clear();
|
||||||
g_on_key_action = nullptr;
|
g_on_key_action = nullptr;
|
||||||
g_user_ptr = nullptr;
|
g_user_ptr = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -54,10 +54,27 @@ int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
|
|||||||
input.type = INPUT_KEYBOARD;
|
input.type = INPUT_KEYBOARD;
|
||||||
input.ki.wVk = (WORD)key_code;
|
input.ki.wVk = (WORD)key_code;
|
||||||
|
|
||||||
if (!is_down) {
|
const UINT scan_code =
|
||||||
input.ki.dwFlags = KEYEVENTF_KEYUP;
|
MapVirtualKeyW(static_cast<UINT>(key_code), MAPVK_VK_TO_VSC_EX);
|
||||||
|
if (scan_code != 0) {
|
||||||
|
input.ki.wVk = 0;
|
||||||
|
input.ki.wScan = static_cast<WORD>(scan_code & 0xFF);
|
||||||
|
input.ki.dwFlags |= KEYEVENTF_SCANCODE;
|
||||||
|
if ((scan_code & 0xFF00) != 0) {
|
||||||
|
input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_down) {
|
||||||
|
input.ki.dwFlags |= KEYEVENTF_KEYUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT sent = SendInput(1, &input, sizeof(INPUT));
|
||||||
|
if (sent != 1) {
|
||||||
|
LOG_WARN("SendInput failed for key_code={}, is_down={}, err={}", key_code,
|
||||||
|
is_down, GetLastError());
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
SendInput(1, &input, sizeof(INPUT));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user