fix(macos): avoid non-selectable IME layouts for remote keys

macOS input methods can expose non-user-selectable keyboard layouts bundled with the input method rather than the user's real selectable keyboard layout. Translating remote key events through those layouts can send IME punctuation semantics to clients instead of the expected ASCII punctuation.

Use the current ASCII-capable keyboard layout when the active input source has no Unicode key layout data and the reported keyboard layout is not directly selectable. Normal selectable keyboard layouts continue to use the existing translation path.

This affects macOS servers forwarding keyboard input to remote clients while an input-method-bundled layout is active.
This commit is contained in:
Momoyama 2026-05-27 18:44:49 +08:00 committed by Nick Bolton
parent ed1306aa5d
commit 9c18070b17

View file

@ -173,6 +173,33 @@ bool isModifier(uint8_t virtualKey)
return (modifiers.find(virtualKey) != modifiers.end()); return (modifiers.find(virtualKey) != modifiers.end());
} }
AutoTISInputSourceRef copyKeyboardLayoutForKeyTranslation()
{
std::lock_guard<std::mutex> lock(g_tisMutex);
AutoTISInputSourceRef keyboardLayout(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
AutoTISInputSourceRef inputSource(TISCopyCurrentKeyboardInputSource(), CFRelease);
const bool inputSourceHasLayout =
inputSource && TISGetInputSourceProperty(inputSource.get(), kTISPropertyUnicodeKeyLayoutData) != nullptr;
CFBooleanRef isSelectCapable = nullptr;
if (keyboardLayout) {
isSelectCapable =
(CFBooleanRef)TISGetInputSourceProperty(keyboardLayout.get(), kTISPropertyInputSourceIsSelectCapable);
}
const bool keyboardLayoutIsSelectCapable = isSelectCapable && CFBooleanGetValue(isSelectCapable);
if (inputSource && keyboardLayout && !inputSourceHasLayout && !keyboardLayoutIsSelectCapable) {
AutoTISInputSourceRef asciiKeyboardLayout(TISCopyCurrentASCIICapableKeyboardLayoutInputSource(), CFRelease);
if (asciiKeyboardLayout) {
return asciiKeyboardLayout;
}
}
return keyboardLayout;
}
} // namespace } // namespace
// //
@ -293,11 +320,10 @@ KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs &ids, KeyModifierMask *maskOut, CG
} }
// get keyboard info // get keyboard info
AutoTISInputSourceRef currentKeyboardLayout(nullptr, CFRelease); AutoTISInputSourceRef currentKeyboardLayout = copyKeyboardLayoutForKeyTranslation();
CFDataRef ref = nullptr; CFDataRef ref = nullptr;
{ {
std::lock_guard<std::mutex> lock(g_tisMutex); std::lock_guard<std::mutex> lock(g_tisMutex);
currentKeyboardLayout = AutoTISInputSourceRef(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
if (currentKeyboardLayout) if (currentKeyboardLayout)
ref = (CFDataRef)TISGetInputSourceProperty(currentKeyboardLayout.get(), kTISPropertyUnicodeKeyLayoutData); ref = (CFDataRef)TISGetInputSourceProperty(currentKeyboardLayout.get(), kTISPropertyUnicodeKeyLayoutData);
} }