fix(mac): protect TIS API calls with a mutex (they are not thread safe)
This commit is contained in:
parent
44c5c15082
commit
426b43fc09
4 changed files with 73 additions and 17 deletions
|
|
@ -56,11 +56,19 @@ std::vector<std::string> AppUtilUnix::getKeyboardLayoutList()
|
||||||
AutoCFDictionary dict(
|
AutoCFDictionary dict(
|
||||||
CFDictionaryCreate(nullptr, (const void **)keys, (const void **)values, 1, nullptr, nullptr), CFRelease
|
CFDictionaryCreate(nullptr, (const void **)keys, (const void **)values, 1, nullptr, nullptr), CFRelease
|
||||||
);
|
);
|
||||||
AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease);
|
AutoCFArray kbds(nullptr, CFRelease);
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
kbds = AutoCFArray(TISCreateInputSourceList(dict.get(), false), CFRelease);
|
||||||
|
}
|
||||||
|
|
||||||
for (CFIndex i = 0; i < CFArrayGetCount(kbds.get()); ++i) {
|
for (CFIndex i = 0; i < CFArrayGetCount(kbds.get()); ++i) {
|
||||||
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(kbds.get(), i);
|
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(kbds.get(), i);
|
||||||
auto layoutLanguages = (CFArrayRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceLanguages);
|
CFArrayRef layoutLanguages = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
layoutLanguages = (CFArrayRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceLanguages);
|
||||||
|
}
|
||||||
char temporaryCString[128] = {0};
|
char temporaryCString[128] = {0};
|
||||||
for (CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) {
|
for (CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) {
|
||||||
auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index);
|
auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index);
|
||||||
|
|
@ -135,8 +143,14 @@ std::string AppUtilUnix::getCurrentLanguageCode()
|
||||||
result = X11LayoutsParser::convertLayoutToISO(m_evdev, result);
|
result = X11LayoutsParser::convertLayoutToISO(m_evdev, result);
|
||||||
|
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
auto layoutLanguages =
|
AutoTISInputSourceRef source(nullptr, CFRelease);
|
||||||
(CFArrayRef)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceLanguages);
|
CFArrayRef layoutLanguages = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
source = AutoTISInputSourceRef(TISCopyCurrentKeyboardInputSource(), CFRelease);
|
||||||
|
if (source)
|
||||||
|
layoutLanguages = (CFArrayRef)TISGetInputSourceProperty(source.get(), kTISPropertyInputSourceLanguages);
|
||||||
|
}
|
||||||
char temporaryCString[128] = {0};
|
char temporaryCString[128] = {0};
|
||||||
for (CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) {
|
for (CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) {
|
||||||
auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index);
|
auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "platform/IOSXKeyResource.h"
|
#include "platform/IOSXKeyResource.h"
|
||||||
|
|
||||||
|
#include "platform/OSXAutoTypes.h"
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
|
|
||||||
KeyID IOSXKeyResource::getKeyID(uint8_t c)
|
KeyID IOSXKeyResource::getKeyID(uint8_t c)
|
||||||
|
|
@ -101,8 +102,14 @@ KeyID IOSXKeyResource::getKeyID(uint8_t c)
|
||||||
str[1] = 0;
|
str[1] = 0;
|
||||||
|
|
||||||
// get current keyboard script
|
// get current keyboard script
|
||||||
TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource();
|
AutoTISInputSourceRef isref(nullptr, CFRelease);
|
||||||
CFArrayRef langs = (CFArrayRef)TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages);
|
CFArrayRef langs = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
isref = AutoTISInputSourceRef(TISCopyCurrentKeyboardInputSource(), CFRelease);
|
||||||
|
if (isref)
|
||||||
|
langs = (CFArrayRef)TISGetInputSourceProperty(isref.get(), kTISPropertyInputSourceLanguages);
|
||||||
|
}
|
||||||
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)CFArrayGetValueAtIndex(langs, 0));
|
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)CFArrayGetValueAtIndex(langs, 0));
|
||||||
// convert to unicode
|
// convert to unicode
|
||||||
CFStringRef cfString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, str, encoding, kCFAllocatorNull);
|
CFStringRef cfString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, str, encoding, kCFAllocatorNull);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@
|
||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
using CFDeallocator = decltype(&CFRelease);
|
using CFDeallocator = decltype(&CFRelease);
|
||||||
using AutoCFArray = std::unique_ptr<const __CFArray, CFDeallocator>;
|
using AutoCFArray = std::unique_ptr<const __CFArray, CFDeallocator>;
|
||||||
using AutoCFDictionary = std::unique_ptr<const __CFDictionary, CFDeallocator>;
|
using AutoCFDictionary = std::unique_ptr<const __CFDictionary, CFDeallocator>;
|
||||||
using AutoTISInputSourceRef = std::unique_ptr<__TISInputSource, CFDeallocator>;
|
using AutoTISInputSourceRef = std::unique_ptr<__TISInputSource, CFDeallocator>;
|
||||||
|
|
||||||
|
inline std::mutex g_tisMutex;
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,14 @@ KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs &ids, KeyModifierMask *maskOut, CG
|
||||||
}
|
}
|
||||||
|
|
||||||
// get keyboard info
|
// get keyboard info
|
||||||
AutoTISInputSourceRef currentKeyboardLayout(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
|
AutoTISInputSourceRef currentKeyboardLayout(nullptr, CFRelease);
|
||||||
|
CFDataRef ref = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
currentKeyboardLayout = AutoTISInputSourceRef(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
|
||||||
|
if (currentKeyboardLayout)
|
||||||
|
ref = (CFDataRef)TISGetInputSourceProperty(currentKeyboardLayout.get(), kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
}
|
||||||
|
|
||||||
if (!currentKeyboardLayout) {
|
if (!currentKeyboardLayout) {
|
||||||
return kKeyNone;
|
return kKeyNone;
|
||||||
|
|
@ -325,7 +332,6 @@ KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs &ids, KeyModifierMask *maskOut, CG
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate via uchr resource
|
// translate via uchr resource
|
||||||
CFDataRef ref = (CFDataRef)TISGetInputSourceProperty(currentKeyboardLayout.get(), kTISPropertyUnicodeKeyLayoutData);
|
|
||||||
const UCKeyboardLayout *layout = (const UCKeyboardLayout *)CFDataGetBytePtr(ref);
|
const UCKeyboardLayout *layout = (const UCKeyboardLayout *)CFDataGetBytePtr(ref);
|
||||||
const bool layoutValid = (layout != nullptr);
|
const bool layoutValid = (layout != nullptr);
|
||||||
|
|
||||||
|
|
@ -427,8 +433,14 @@ KeyModifierMask OSXKeyState::pollActiveModifiers() const
|
||||||
|
|
||||||
int32_t OSXKeyState::pollActiveGroup() const
|
int32_t OSXKeyState::pollActiveGroup() const
|
||||||
{
|
{
|
||||||
AutoTISInputSourceRef keyboardLayout(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
|
AutoTISInputSourceRef keyboardLayout(nullptr, CFRelease);
|
||||||
CFDataRef id = (CFDataRef)TISGetInputSourceProperty(keyboardLayout.get(), kTISPropertyInputSourceID);
|
CFDataRef id = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
keyboardLayout = AutoTISInputSourceRef(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease);
|
||||||
|
if (keyboardLayout)
|
||||||
|
id = (CFDataRef)TISGetInputSourceProperty(keyboardLayout.get(), kTISPropertyInputSourceID);
|
||||||
|
}
|
||||||
|
|
||||||
GroupMap::const_iterator i = m_groupMap.find(id);
|
GroupMap::const_iterator i = m_groupMap.find(id);
|
||||||
if (i != m_groupMap.end()) {
|
if (i != m_groupMap.end()) {
|
||||||
|
|
@ -463,7 +475,11 @@ void OSXKeyState::getKeyMap(deskflow::KeyMap &keyMap)
|
||||||
numGroups = CFArrayGetCount(m_groups.get());
|
numGroups = CFArrayGetCount(m_groups.get());
|
||||||
for (int32_t g = 0; g < numGroups; ++g) {
|
for (int32_t g = 0; g < numGroups; ++g) {
|
||||||
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g);
|
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g);
|
||||||
CFDataRef id = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceID);
|
CFDataRef id = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
id = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceID);
|
||||||
|
}
|
||||||
m_groupMap[id] = g;
|
m_groupMap[id] = g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -479,7 +495,11 @@ void OSXKeyState::getKeyMap(deskflow::KeyMap &keyMap)
|
||||||
// add regular keys
|
// add regular keys
|
||||||
// try uchr resource first
|
// try uchr resource first
|
||||||
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g);
|
TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g);
|
||||||
CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyUnicodeKeyLayoutData);
|
CFDataRef resourceRef = nullptr;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
resourceRef = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
}
|
||||||
|
|
||||||
layoutValid = resourceRef != nullptr;
|
layoutValid = resourceRef != nullptr;
|
||||||
if (layoutValid)
|
if (layoutValid)
|
||||||
|
|
@ -853,7 +873,11 @@ bool OSXKeyState::getGroups(AutoCFArray &groups) const
|
||||||
AutoCFDictionary dict(
|
AutoCFDictionary dict(
|
||||||
CFDictionaryCreate(nullptr, (const void **)keys, (const void **)values, 1, nullptr, nullptr), CFRelease
|
CFDictionaryCreate(nullptr, (const void **)keys, (const void **)values, 1, nullptr, nullptr), CFRelease
|
||||||
);
|
);
|
||||||
AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease);
|
AutoCFArray kbds(nullptr, CFRelease);
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
kbds = AutoCFArray(TISCreateInputSourceList(dict.get(), false), CFRelease);
|
||||||
|
}
|
||||||
|
|
||||||
if (CFArrayGetCount(kbds.get()) > 0) {
|
if (CFArrayGetCount(kbds.get()) > 0) {
|
||||||
groups = std::move(kbds);
|
groups = std::move(kbds);
|
||||||
|
|
@ -872,15 +896,23 @@ void OSXKeyState::setGroup(int32_t group)
|
||||||
LOG_WARN("needed keyboard layout is null");
|
LOG_WARN("needed keyboard layout is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto canBeSetted = (CFBooleanRef
|
CFBooleanRef canBeSetted = nullptr;
|
||||||
)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceIsEnableCapable);
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
AutoTISInputSourceRef source(TISCopyCurrentKeyboardInputSource(), CFRelease);
|
||||||
|
if (source)
|
||||||
|
canBeSetted = (CFBooleanRef)TISGetInputSourceProperty(source.get(), kTISPropertyInputSourceIsEnableCapable);
|
||||||
|
}
|
||||||
if (!canBeSetted) {
|
if (!canBeSetted) {
|
||||||
LOG_WARN("needed keyboard layout is disabled for programmatically selection");
|
LOG_WARN("needed keyboard layout is disabled for programmatically selection");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TISSelectInputSource(keyboardLayout) != noErr) {
|
{
|
||||||
LOG_WARN("failed to set needed keyboard layout");
|
std::lock_guard<std::mutex> lock(g_tisMutex);
|
||||||
|
if (TISSelectInputSource(keyboardLayout) != noErr) {
|
||||||
|
LOG_WARN("failed to set needed keyboard layout");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG1("keyboard layout change to %d", group);
|
LOG_DEBUG1("keyboard layout change to %d", group);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue