Skip to content

Commit e03487b

Browse files
committed
Fix Japanese keyboard mapping
1 parent 15a37d3 commit e03487b

4 files changed

Lines changed: 136 additions & 15 deletions

File tree

src/platform/linux/uhid_backend.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,19 @@ namespace lvh::detail {
535535
return it->second;
536536
}
537537

538-
int key_code_to_linux(KeyboardKeyCode key_code) {
539-
static constexpr std::array<std::pair<KeyboardKeyCode, int>, 47> special_keys {{
538+
int key_code_to_linux(KeyboardKeyCode key_code, bool uses_normalized_key_code) {
539+
if (!uses_normalized_key_code) {
540+
switch (key_code) {
541+
case 0xDC:
542+
return KEY_YEN;
543+
case 0xE2:
544+
return KEY_RO;
545+
default:
546+
break;
547+
}
548+
}
549+
550+
static constexpr std::array<std::pair<KeyboardKeyCode, int>, 50> special_keys {{
540551
{0x08, KEY_BACKSPACE},
541552
{0x09, KEY_TAB},
542553
{0x0D, KEY_ENTER},
@@ -547,7 +558,10 @@ namespace lvh::detail {
547558
{0x12, KEY_LEFTALT},
548559
{0xA4, KEY_LEFTALT},
549560
{0x14, KEY_CAPSLOCK},
561+
{0x15, KEY_KATAKANAHIRAGANA},
550562
{0x1B, KEY_ESC},
563+
{0x1C, KEY_HENKAN},
564+
{0x1D, KEY_MUHENKAN},
551565
{0x20, KEY_SPACE},
552566
{0x21, KEY_PAGEUP},
553567
{0x22, KEY_PAGEDOWN},
@@ -1442,7 +1456,7 @@ namespace lvh::detail {
14421456

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

20362050
#if defined(LIBVIRTUALHID_HAVE_XTEST)
2037-
KeySym key_code_to_keysym(KeyboardKeyCode key_code) {
2038-
static constexpr std::array<std::pair<KeyboardKeyCode, KeySym>, 45> special_keysyms {{
2051+
KeySym key_code_to_keysym(KeyboardKeyCode key_code, bool uses_normalized_key_code) {
2052+
if (!uses_normalized_key_code) {
2053+
switch (key_code) {
2054+
case 0xDC:
2055+
return XK_yen;
2056+
case 0xE2:
2057+
return XK_backslash;
2058+
default:
2059+
break;
2060+
}
2061+
}
2062+
2063+
static constexpr std::array<std::pair<KeyboardKeyCode, KeySym>, 49> special_keysyms {{
20392064
{0x08, XK_BackSpace},
20402065
{0x09, XK_Tab},
20412066
{0x0D, XK_Return},
@@ -2046,7 +2071,10 @@ namespace lvh::detail {
20462071
{0x12, XK_Alt_L},
20472072
{0xA4, XK_Alt_L},
20482073
{0x14, XK_Caps_Lock},
2074+
{0x15, XK_Hiragana_Katakana},
20492075
{0x1B, XK_Escape},
2076+
{0x1C, XK_Henkan},
2077+
{0x1D, XK_Muhenkan},
20502078
{0x20, XK_space},
20512079
{0x21, XK_Page_Up},
20522080
{0x22, XK_Page_Down},
@@ -2081,6 +2109,7 @@ namespace lvh::detail {
20812109
{0xDC, XK_backslash},
20822110
{0xDD, XK_bracketright},
20832111
{0xDE, XK_apostrophe},
2112+
{0xE2, XK_backslash},
20842113
}};
20852114

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

2172-
const auto keysym = key_code_to_keysym(event.key_code);
2201+
const auto keysym = key_code_to_keysym(event.key_code, event.uses_normalized_key_code);
21732202
if (keysym == NoSymbol) {
21742203
return OperationStatus::failure(ErrorCode::invalid_argument, "keyboard key code is not supported by XTest fallback");
21752204
}

src/platform/windows/keylayout.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ namespace lvh::detail {
3737
56, /* 0x12 */
3838
0, /* 0x13 */
3939
58, /* 0x14 */
40-
0, /* 0x15 */
40+
0x70, /* 0x15 VK_KANA */
4141
0, /* 0x16 */
4242
0, /* 0x17 */
4343
0, /* 0x18 */
4444
0, /* 0x19 */
4545
0, /* 0x1a */
4646
1, /* 0x1b */
47-
0, /* 0x1c */
48-
0, /* 0x1d */
47+
0x79, /* 0x1c VK_CONVERT (Henkan) */
48+
0x7B, /* 0x1d VK_NONCONVERT (Muhenkan) */
4949
0, /* 0x1e */
5050
0, /* 0x1f */
5151
57, /* 0x20 */

src/platform/windows/windows_backend.cpp

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,88 @@ namespace lvh::detail {
466466
}
467467
}
468468

469+
/**
470+
* @brief Whether a scan code is sent with the E0 extended prefix.
471+
*
472+
* @param scan_code Low byte of the scan code.
473+
* @return True when the scan code requires `KEYEVENTF_EXTENDEDKEY`.
474+
*/
475+
bool extended_scan_code(WORD scan_code) {
476+
switch (scan_code) {
477+
case 0x1C:
478+
case 0x35:
479+
case 0x37:
480+
case 0x38:
481+
case 0x47:
482+
case 0x48:
483+
case 0x49:
484+
case 0x4B:
485+
case 0x4D:
486+
case 0x50:
487+
case 0x51:
488+
case 0x52:
489+
case 0x53:
490+
case 0x5B:
491+
case 0x5C:
492+
case 0x5D:
493+
case 0x5F:
494+
case 0x64:
495+
case 0x65:
496+
case 0x66:
497+
case 0x67:
498+
case 0x68:
499+
case 0x69:
500+
case 0x6A:
501+
case 0x6B:
502+
case 0x6C:
503+
case 0x6D:
504+
case 0x6E:
505+
case 0x6F:
506+
case 0x70:
507+
case 0x71:
508+
case 0x72:
509+
case 0x73:
510+
case 0x74:
511+
case 0x75:
512+
case 0x76:
513+
case 0x77:
514+
case 0x78:
515+
case 0x79:
516+
case 0x7A:
517+
case 0x7B:
518+
case 0x7C:
519+
case 0x7D:
520+
case 0x7E:
521+
case 0x7F:
522+
return true;
523+
default:
524+
return false;
525+
}
526+
}
527+
528+
/**
529+
* @brief Map a virtual key to a scan code using the active keyboard layout.
530+
*
531+
* @param key_code Windows virtual key code.
532+
* @return Scan code and extended-prefix flag from `MapVirtualKeyW`.
533+
*/
534+
struct MappedScanCode {
535+
WORD scan_code = 0;
536+
bool extended = false;
537+
};
538+
539+
MappedScanCode map_virtual_key_to_scan_code(KeyboardKeyCode key_code) {
540+
const auto mapped = ::MapVirtualKeyW(key_code, MAPVK_VK_TO_VSC);
541+
if (mapped == 0U) {
542+
return {};
543+
}
544+
545+
return {
546+
.scan_code = static_cast<WORD>(mapped & 0xFFU),
547+
.extended = (mapped & 0xFF00U) != 0U,
548+
};
549+
}
550+
469551
bool can_map_virtual_key_to_scan_code(KeyboardKeyCode key_code) {
470552
return key_code != VK_LWIN && key_code != VK_RWIN && key_code != VK_PAUSE;
471553
}
@@ -1272,23 +1354,33 @@ namespace lvh::detail {
12721354
INPUT input {};
12731355
input.type = INPUT_KEYBOARD;
12741356
input.ki.wVk = event.key_code;
1357+
auto use_extended_key = false;
1358+
12751359
if (event.scan_code != 0U) {
12761360
input.ki.wVk = 0;
12771361
input.ki.wScan = event.scan_code;
12781362
input.ki.dwFlags |= KEYEVENTF_SCANCODE;
1363+
use_extended_key = extended_scan_code(event.scan_code);
12791364
} else {
1365+
WORD scan_code = 0;
12801366
if (event.uses_normalized_key_code) {
1281-
input.ki.wScan = windows_us_english_scan_code(event.key_code);
1282-
} else if (event.prefer_native_scan_code && can_map_virtual_key_to_scan_code(event.key_code)) {
1283-
input.ki.wScan = static_cast<WORD>(::MapVirtualKeyW(event.key_code, MAPVK_VK_TO_VSC));
1367+
scan_code = windows_us_english_scan_code(event.key_code);
1368+
use_extended_key = extended_key(event.key_code) || extended_scan_code(scan_code);
1369+
} else if (can_map_virtual_key_to_scan_code(event.key_code)) {
1370+
// Non-normalized keys use the host's active keyboard layout.
1371+
const auto mapped = map_virtual_key_to_scan_code(event.key_code);
1372+
scan_code = mapped.scan_code;
1373+
use_extended_key = mapped.extended;
12841374
}
12851375

1286-
if (input.ki.wScan != 0U) {
1376+
if (scan_code != 0U) {
12871377
input.ki.wVk = 0;
1378+
input.ki.wScan = scan_code;
12881379
input.ki.dwFlags |= KEYEVENTF_SCANCODE;
12891380
}
12901381
}
1291-
if (extended_key(event.key_code)) {
1382+
1383+
if (use_extended_key) {
12921384
input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
12931385
}
12941386
if (!event.pressed) {

tests/fixtures/linux_backend_test_hooks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ namespace lvh::detail::test {
962962
}
963963

964964
int linux_key_code(KeyboardKeyCode key_code) {
965-
return key_code_to_linux(key_code);
965+
return key_code_to_linux(key_code, true);
966966
}
967967

968968
int linux_mouse_button(MouseButton button) {

0 commit comments

Comments
 (0)