Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions src/platform/linux/uhid_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,19 @@ namespace lvh::detail {
return it->second;
}

int key_code_to_linux(KeyboardKeyCode key_code) {
static constexpr std::array<std::pair<KeyboardKeyCode, int>, 47> special_keys {{
int key_code_to_linux(KeyboardKeyCode key_code, bool uses_normalized_key_code) {
if (!uses_normalized_key_code) {
switch (key_code) {
case 0xDC:
return KEY_YEN;
case 0xE2:
return KEY_RO;
default:
break;
}
}

static constexpr std::array<std::pair<KeyboardKeyCode, int>, 50> special_keys {{
{0x08, KEY_BACKSPACE},
{0x09, KEY_TAB},
{0x0D, KEY_ENTER},
Expand All @@ -547,7 +558,10 @@ namespace lvh::detail {
{0x12, KEY_LEFTALT},
{0xA4, KEY_LEFTALT},
{0x14, KEY_CAPSLOCK},
{0x15, KEY_KATAKANAHIRAGANA},
{0x1B, KEY_ESC},
{0x1C, KEY_HENKAN},
{0x1D, KEY_MUHENKAN},
{0x20, KEY_SPACE},
{0x21, KEY_PAGEUP},
{0x22, KEY_PAGEDOWN},
Expand Down Expand Up @@ -1442,7 +1456,7 @@ namespace lvh::detail {

private:
OperationStatus emit_keyboard_event(const KeyboardEvent &event) {
const auto linux_key = key_code_to_linux(event.key_code);
const auto linux_key = key_code_to_linux(event.key_code, event.uses_normalized_key_code);
if (linux_key < 0) {
return OperationStatus::failure(ErrorCode::invalid_argument, "keyboard key code is not supported by the Linux backend");
}
Expand Down Expand Up @@ -2034,8 +2048,19 @@ namespace lvh::detail {
};

#if defined(LIBVIRTUALHID_HAVE_XTEST)
KeySym key_code_to_keysym(KeyboardKeyCode key_code) {
static constexpr std::array<std::pair<KeyboardKeyCode, KeySym>, 45> special_keysyms {{
KeySym key_code_to_keysym(KeyboardKeyCode key_code, bool uses_normalized_key_code) {
if (!uses_normalized_key_code) {
switch (key_code) {
case 0xDC:
return XK_yen;
case 0xE2:
return XK_backslash;
default:
break;
}
}

static constexpr std::array<std::pair<KeyboardKeyCode, KeySym>, 49> special_keysyms {{
{0x08, XK_BackSpace},
{0x09, XK_Tab},
{0x0D, XK_Return},
Expand All @@ -2046,7 +2071,10 @@ namespace lvh::detail {
{0x12, XK_Alt_L},
{0xA4, XK_Alt_L},
{0x14, XK_Caps_Lock},
{0x15, XK_Hiragana_Katakana},
{0x1B, XK_Escape},
{0x1C, XK_Henkan},
{0x1D, XK_Muhenkan},
{0x20, XK_space},
{0x21, XK_Page_Up},
{0x22, XK_Page_Down},
Expand Down Expand Up @@ -2081,6 +2109,7 @@ namespace lvh::detail {
{0xDC, XK_backslash},
{0xDD, XK_bracketright},
{0xDE, XK_apostrophe},
{0xE2, XK_backslash},
}};

if (const auto keysym = mapped_keyboard_code(key_code, special_keysyms); keysym.has_value()) {
Expand Down Expand Up @@ -2169,7 +2198,7 @@ namespace lvh::detail {
return OperationStatus::failure(ErrorCode::device_closed, "XTest keyboard is closed");
}

const auto keysym = key_code_to_keysym(event.key_code);
const auto keysym = key_code_to_keysym(event.key_code, event.uses_normalized_key_code);
if (keysym == NoSymbol) {
return OperationStatus::failure(ErrorCode::invalid_argument, "keyboard key code is not supported by XTest fallback");
}
Expand Down
6 changes: 3 additions & 3 deletions src/platform/windows/keylayout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ namespace lvh::detail {
56, /* 0x12 */
0, /* 0x13 */
58, /* 0x14 */
0, /* 0x15 */
0x70, /* 0x15 VK_KANA */
0, /* 0x16 */
0, /* 0x17 */
0, /* 0x18 */
0, /* 0x19 */
0, /* 0x1a */
1, /* 0x1b */
0, /* 0x1c */
0, /* 0x1d */
0x79, /* 0x1c VK_CONVERT (Henkan) */
0x7B, /* 0x1d VK_NONCONVERT (Muhenkan) */
0, /* 0x1e */
0, /* 0x1f */
57, /* 0x20 */
Expand Down
102 changes: 97 additions & 5 deletions src/platform/windows/windows_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,88 @@
}
}

/**
* @brief Whether a scan code is sent with the E0 extended prefix.
*
* @param scan_code Low byte of the scan code.
* @return True when the scan code requires `KEYEVENTF_EXTENDEDKEY`.
*/
bool extended_scan_code(WORD scan_code) {
switch (scan_code) {

Check warning on line 476 in src/platform/windows/windows_backend.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Reduce the number of switch cases from 46 to at most 30.

See more on https://sonarcloud.io/project/issues?id=LizardByte_libvirtualhid&issues=AaApSwqXH7VZS0qiPGEW&open=AaApSwqXH7VZS0qiPGEW&pullRequest=101
case 0x1C:
case 0x35:
case 0x37:
case 0x38:
case 0x47:
case 0x48:
case 0x49:
case 0x4B:
case 0x4D:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5F:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
case 0x68:
case 0x69:
case 0x6A:
case 0x6B:
case 0x6C:
case 0x6D:
case 0x6E:
case 0x6F:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x76:
case 0x77:
case 0x78:
case 0x79:
case 0x7A:
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
case 0x7F:
return true;
default:
return false;
}
}

/**
* @brief Map a virtual key to a scan code using the active keyboard layout.
*
* @param key_code Windows virtual key code.
* @return Scan code and extended-prefix flag from `MapVirtualKeyW`.
*/
struct MappedScanCode {
WORD scan_code = 0;
bool extended = false;
};

MappedScanCode map_virtual_key_to_scan_code(KeyboardKeyCode key_code) {
const auto mapped = ::MapVirtualKeyW(key_code, MAPVK_VK_TO_VSC);
if (mapped == 0U) {
return {};
}

return {
.scan_code = static_cast<WORD>(mapped & 0xFFU),
.extended = (mapped & 0xFF00U) != 0U,
};
}

bool can_map_virtual_key_to_scan_code(KeyboardKeyCode key_code) {
return key_code != VK_LWIN && key_code != VK_RWIN && key_code != VK_PAUSE;
}
Expand Down Expand Up @@ -1272,23 +1354,33 @@
INPUT input {};
input.type = INPUT_KEYBOARD;
input.ki.wVk = event.key_code;
auto use_extended_key = false;

if (event.scan_code != 0U) {
input.ki.wVk = 0;
input.ki.wScan = event.scan_code;
input.ki.dwFlags |= KEYEVENTF_SCANCODE;
use_extended_key = extended_scan_code(event.scan_code);
} else {
WORD scan_code = 0;
if (event.uses_normalized_key_code) {
input.ki.wScan = windows_us_english_scan_code(event.key_code);
} else if (event.prefer_native_scan_code && can_map_virtual_key_to_scan_code(event.key_code)) {
input.ki.wScan = static_cast<WORD>(::MapVirtualKeyW(event.key_code, MAPVK_VK_TO_VSC));
scan_code = windows_us_english_scan_code(event.key_code);
use_extended_key = extended_key(event.key_code) || extended_scan_code(scan_code);
} else if (can_map_virtual_key_to_scan_code(event.key_code)) {
// Non-normalized keys use the host's active keyboard layout.
const auto mapped = map_virtual_key_to_scan_code(event.key_code);
scan_code = mapped.scan_code;
use_extended_key = mapped.extended;
}

if (input.ki.wScan != 0U) {
if (scan_code != 0U) {
input.ki.wVk = 0;
input.ki.wScan = scan_code;
input.ki.dwFlags |= KEYEVENTF_SCANCODE;
}
}
if (extended_key(event.key_code)) {

if (use_extended_key) {
input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
}
if (!event.pressed) {
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/linux_backend_test_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ namespace lvh::detail::test {
}

int linux_key_code(KeyboardKeyCode key_code) {
return key_code_to_linux(key_code);
return key_code_to_linux(key_code, true);
}

int linux_mouse_button(MouseButton button) {
Expand Down