Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
144 lines
3.4 KiB
C++
144 lines
3.4 KiB
C++
// This file is part of Desktop App Toolkit,
|
|
// a set of libraries for developing nice desktop applications.
|
|
//
|
|
// For license and copyright information please follow this link:
|
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
|
//
|
|
#include "spellcheck/platform/win/language_win.h"
|
|
|
|
#include "base/platform/win/base_windows_safe_library.h"
|
|
|
|
#include <Windows.h>
|
|
#include <ElsCore.h>
|
|
#include <ElsSrvc.h> // ELS_GUID_LANGUAGE_DETECTION.
|
|
|
|
namespace Platform::Language {
|
|
namespace {
|
|
|
|
HRESULT (__stdcall *MappingGetServices)(
|
|
_In_opt_ PMAPPING_ENUM_OPTIONS pOptions,
|
|
_Out_ PMAPPING_SERVICE_INFO *prgServices,
|
|
_Out_ DWORD *pdwServicesCount
|
|
);
|
|
|
|
HRESULT (__stdcall *MappingFreeServices)(
|
|
_In_ PMAPPING_SERVICE_INFO pServiceInfo
|
|
);
|
|
|
|
HRESULT (__stdcall *MappingRecognizeText)(
|
|
_In_ PMAPPING_SERVICE_INFO pServiceInfo,
|
|
_In_reads_(dwLength) LPCWSTR pszText,
|
|
_In_ DWORD dwLength,
|
|
_In_ DWORD dwIndex,
|
|
_In_opt_ PMAPPING_OPTIONS pOptions,
|
|
_Inout_ PMAPPING_PROPERTY_BAG pbag
|
|
);
|
|
|
|
HRESULT (__stdcall *MappingFreePropertyBag)(
|
|
_In_ PMAPPING_PROPERTY_BAG pBag
|
|
);
|
|
|
|
[[nodiscard]] inline bool Supported() {
|
|
static const auto Result = [] {
|
|
#define LOAD_SYMBOL(lib, name) base::Platform::LoadMethod(lib, #name, name)
|
|
const auto els = base::Platform::SafeLoadLibrary(L"elscore.dll");
|
|
return LOAD_SYMBOL(els, MappingGetServices)
|
|
&& LOAD_SYMBOL(els, MappingRecognizeText)
|
|
&& LOAD_SYMBOL(els, MappingFreeServices)
|
|
&& LOAD_SYMBOL(els, MappingFreePropertyBag);
|
|
#undef LOAD_SYMBOL
|
|
}();
|
|
return Result;
|
|
}
|
|
|
|
struct unique_services final {
|
|
operator MAPPING_SERVICE_INFO *() {
|
|
return services;
|
|
}
|
|
MAPPING_SERVICE_INFO **operator&() {
|
|
return &services;
|
|
}
|
|
MAPPING_SERVICE_INFO *services = nullptr;
|
|
unique_services() = default;
|
|
unique_services(unique_services const &other) = delete;
|
|
~unique_services() {
|
|
if (services) {
|
|
MappingFreeServices(services);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct unique_bag final : public MAPPING_PROPERTY_BAG {
|
|
unique_bag() : MAPPING_PROPERTY_BAG{} {
|
|
}
|
|
unique_bag(unique_bag const &other) = delete;
|
|
~unique_bag() {
|
|
MappingFreePropertyBag(this);
|
|
}
|
|
};
|
|
|
|
inline void MappingRecognizeTextFromService(
|
|
REFGUID service,
|
|
LPCWSTR text,
|
|
DWORD length,
|
|
unique_bag &bag) {
|
|
auto options = MAPPING_ENUM_OPTIONS{};
|
|
options.Size = sizeof(options);
|
|
options.pGuid = const_cast<GUID*>(&service);
|
|
|
|
auto dwServicesCount = DWORD(0);
|
|
auto services = unique_services();
|
|
|
|
const auto hr = MappingGetServices(&options, &services, &dwServicesCount);
|
|
if (FAILED(hr)) {
|
|
return;
|
|
}
|
|
|
|
bag.Size = sizeof(bag);
|
|
MappingRecognizeText(services, text, length, 0, nullptr, &bag);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void RecognizeTextLanguages(
|
|
LPCWSTR text,
|
|
DWORD length,
|
|
Fn<void(LPCWSTR, int)> &&callback) {
|
|
if (!length) {
|
|
return;
|
|
}
|
|
|
|
auto bag = unique_bag();
|
|
MappingRecognizeTextFromService(
|
|
ELS_GUID_LANGUAGE_DETECTION,
|
|
text,
|
|
length,
|
|
bag);
|
|
|
|
auto pos = reinterpret_cast<LPCWSTR>(bag.prgResultRanges[0].pData);
|
|
for (; *pos;) {
|
|
const auto len = wcslen(pos);
|
|
if (len >= 2) {
|
|
callback(pos, len);
|
|
}
|
|
pos += (len + 1);
|
|
}
|
|
}
|
|
|
|
Id Recognize(QStringView text) {
|
|
if (Supported()) {
|
|
auto locales = std::vector<QLocale>();
|
|
RecognizeTextLanguages(
|
|
(LPCWSTR)text.utf16(),
|
|
DWORD(text.size()),
|
|
[&](LPCWSTR r, int length) {
|
|
// Cut complex result, e.g. "sr-Cyrl".
|
|
locales.emplace_back(QString::fromWCharArray(r, 2));
|
|
});
|
|
return { locales[0].language() };
|
|
}
|
|
return {};
|
|
}
|
|
|
|
} // namespace Platform::Language
|