deskflow/src/lib/platform/OSXKeyLayoutResource.cpp

94 lines
2.7 KiB
C++
Raw Normal View History

/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "platform/OSXKeyLayoutResource.h"
// there are 128 virtual key codes and 32 modifier combinations (the
// right-handed modifier bits are ignored, matching the uchr parser).
static const uint32_t s_numButtons = 128;
static const uint32_t s_numModifierCombinations = 32;
OSXKeyLayoutResource::OSXKeyLayoutResource(const void *resource, uint32_t keyboardType)
: m_layout(static_cast<const UCKeyboardLayout *>(resource)),
m_keyboardType(keyboardType)
{
}
bool OSXKeyLayoutResource::isValid() const
{
return m_layout != nullptr;
}
uint32_t OSXKeyLayoutResource::getNumModifierCombinations() const
{
return s_numModifierCombinations;
}
uint32_t OSXKeyLayoutResource::getNumTables() const
{
// one table per modifier combination
return s_numModifierCombinations;
}
uint32_t OSXKeyLayoutResource::getNumButtons() const
{
return s_numButtons;
}
uint32_t OSXKeyLayoutResource::getTableForModifier(uint32_t mask) const
{
// the modifier combination is the table
return (mask < s_numModifierCombinations) ? mask : 0;
}
KeyID OSXKeyLayoutResource::getKey(uint32_t table, uint32_t button) const
{
if (m_layout == nullptr || button >= s_numButtons) {
return kKeyNone;
}
// UCKeyTranslate's modifier key state uses the same low five bits as our
// table index (cmd, shift, caps, option, control).
const UInt32 modifierState = table;
UInt32 deadKeyState = 0;
UniChar chars[4] = {0};
UniCharCount count = 0;
OSStatus status = UCKeyTranslate(
m_layout, static_cast<UInt16>(button), kUCKeyActionDown, modifierState, m_keyboardType, 0, &deadKeyState,
sizeof(chars) / sizeof(chars[0]), &count, chars
);
if (status != noErr) {
return kKeyNone;
}
if (count == 0) {
// no output. a non-zero dead-key state means this is a dead key: resolve
// it to its spacing character by following it with a space, then convert
// to the dead KeyID.
if (deadKeyState == 0) {
return kKeyNone;
}
UniChar spaceChars[4] = {0};
UniCharCount spaceCount = 0;
status = UCKeyTranslate(
m_layout, kVK_Space, kUCKeyActionDown, 0, m_keyboardType, 0, &deadKeyState,
sizeof(spaceChars) / sizeof(spaceChars[0]), &spaceCount, spaceChars
);
if (status != noErr || spaceCount != 1) {
return kKeyNone;
}
return deskflow::KeyMap::getDeadKey(unicharToKeyID(spaceChars[0]));
}
// no support for multi-character output (matches the uchr parser).
if (count != 1) {
return kKeyNone;
}
return unicharToKeyID(chars[0]);
}