Support for dynamic keyboard shortcuts added

This commit is contained in:
Simon Rozman 2016-03-02 12:29:54 +01:00
parent f3c0e83d04
commit 5398ccbd5e
14 changed files with 575 additions and 91 deletions

View File

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\lib\wxExtend\include;..\lib\stdex\include;..\lib\libZRCola\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\lib\wxExtend\include;..\lib\stdex\include;..\lib\libZRCola\include;..\lib\libZRColaUI\include</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>

View File

@ -57,6 +57,9 @@
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\lib\libZRColaUI\build\libZRColaUI.vcxproj">
<Project>{c0a84bd2-3870-4cd6-b281-0ab322e3c579}</Project>
</ProjectReference>
<ProjectReference Include="..\lib\libZRCola\build\libZRCola.vcxproj">
<Project>{3c61929e-7289-4101-8d0a-da22d6e1aea8}</Project>
</ProjectReference>

View File

@ -29,10 +29,13 @@ ZRCola::DBSource::~DBSource()
{
if (m_db)
m_db->Close();
if (m_locale)
_free_locale(m_locale);
}
bool ZRCola::DBSource::Open(LPCTSTR _filename)
bool ZRCola::DBSource::Open(LPCTSTR filename)
{
wxASSERT_MSG(!m_db, wxT("database already open"));
@ -43,20 +46,21 @@ bool ZRCola::DBSource::Open(LPCTSTR _filename)
std::wstring cn;
cn = L"Driver={Microsoft Access Driver (*.mdb)};";
cn += L"Dbq=";
cn += _filename;
cn += filename;
cn += L";Uid=;Pwd=;";
hr = m_db->Open(ATL::CComBSTR(cn.c_str()));
if (SUCCEEDED(hr)) {
// Database open and ready.
filename = _filename;
m_filename = filename;
m_locale = _create_locale(LC_ALL, "Slovenian_Slovenia.1250");
return true;
} else {
_ftprintf(stderr, wxT("%s: error ZCC0011: Could not open database (0x%x).\n"), (LPCTSTR)_filename, hr);
_ftprintf(stderr, wxT("%s: error ZCC0011: Could not open database (0x%x).\n"), (LPCTSTR)filename, hr);
LogErrors();
}
m_db.Release();
} else
_ftprintf(stderr, wxT("%s: error ZCC0012: Creating ADOConnection object failed (0x%x).\n"), (LPCTSTR)_filename, hr);
_ftprintf(stderr, wxT("%s: error ZCC0012: Creating ADOConnection object failed (0x%x).\n"), (LPCTSTR)filename, hr);
return false;
}
@ -95,7 +99,38 @@ void ZRCola::DBSource::LogErrors() const
}
bool ZRCola::DBSource::GetUnicodeString(const CComPtr<ADOField>& f, std::wstring& str) const
bool ZRCola::DBSource::GetUnicodeCharacter(const ATL::CComPtr<ADOField>& f, wchar_t& chr) const
{
wxASSERT_MSG(f, wxT("field is empty"));
CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
// Parse the field. Must be exactly one Unicode code.
wxVERIFY(SUCCEEDED(v.ChangeType(VT_BSTR)));
UINT i = 0, n = ::SysStringLen(V_BSTR(&v));
chr = 0;
for (; i < n && V_BSTR(&v)[i]; i++) {
if (L'0' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'9') chr = chr*0x10 + (V_BSTR(&v)[i] - L'0');
else if (L'A' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'F') chr = chr*0x10 + (V_BSTR(&v)[i] - L'A' + 10);
else if (L'a' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'f') chr = chr*0x10 + (V_BSTR(&v)[i] - L'a' + 10);
else break;
}
if (i <= 0 && 4 < i) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0030: Syntax error in \"%.*ls\" field (\"%.*ls\"). Unicode code must be one to four hexadecimal characters long.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
} else if (i != n) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0031: Syntax error in \"%.*ls\" field (\"%.*ls\"). Extra trailing characters.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
}
return true;
}
bool ZRCola::DBSource::GetUnicodeString(const ATL::CComPtr<ADOField>& f, std::wstring& str) const
{
wxASSERT_MSG(f, wxT("field is empty"));
@ -117,44 +152,63 @@ bool ZRCola::DBSource::GetUnicodeString(const CComPtr<ADOField>& f, std::wstring
}
if (j <= 0 || 4 < j) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0020: Syntax error in \"%.*ls\" field (\"%.*ls\"). Unicode code must be one to four hexadecimal characters long.\n"), filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
_ftprintf(stderr, wxT("%s: error ZCC0020: Syntax error in \"%.*ls\" field (\"%.*ls\"). Unicode code must be one to four hexadecimal characters long.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
}
str += c;
// Skip delimiter(s) and whitespace.
for (; i < n && V_BSTR(&v)[i] && (V_BSTR(&v)[i] == L'+' || iswspace(V_BSTR(&v)[i])); i++);
for (; i < n && V_BSTR(&v)[i] && (V_BSTR(&v)[i] == L'+' || _iswspace_l(V_BSTR(&v)[i], m_locale)); i++);
}
return true;
}
bool ZRCola::DBSource::GetUnicodeCharacter(const CComPtr<ADOField>& f, wchar_t& chr) const
bool ZRCola::DBSource::GetKeySequence(const ATL::CComPtr<ADOField>& f, std::vector<keyseq::keycode>& seq) const
{
wxASSERT_MSG(f, wxT("field is empty"));
CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
// Parse the field. Must be exactly one Unicode code.
wxVERIFY(SUCCEEDED(v.ChangeType(VT_BSTR)));
UINT i = 0, n = ::SysStringLen(V_BSTR(&v));
chr = 0;
for (; i < n && V_BSTR(&v)[i]; i++) {
if (L'0' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'9') chr = chr*0x10 + (V_BSTR(&v)[i] - L'0');
else if (L'A' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'F') chr = chr*0x10 + (V_BSTR(&v)[i] - L'A' + 10);
else if (L'a' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'f') chr = chr*0x10 + (V_BSTR(&v)[i] - L'a' + 10);
else break;
}
if (i <= 0 && 4 < i) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0030: Syntax error in \"%.*ls\" field (\"%.*ls\"). Unicode code must be one to four hexadecimal characters long.\n"), filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
} else if (i != n) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0031: Syntax error in \"%.*ls\" field (\"%.*ls\"). Extra trailing characters.\n"), filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
// Convert to uppercase.
_wcsupr_l(V_BSTR(&v), m_locale);
// Parse the field. Must be comma delimited sequence of key codes.
seq.clear();
for (UINT i = 0, n = ::SysStringLen(V_BSTR(&v)); i < n && V_BSTR(&v)[i];) {
keyseq::keycode kc = {};
while (i < n && V_BSTR(&v)[i]) {
// Parse key code.
static const wchar_t str_shift[] = L"SHIFT+", str_ctrl[] = L"CTRL+", str_alt[] = L"ALT+";
if (i + _countof(str_shift) <= n && wmemcmp(V_BSTR(&v) + i, str_shift, _countof(str_shift) - 1) == 0) {
kc.shift = true;
i += _countof(str_shift) - 1;
} else if (i + _countof(str_ctrl) <= n && wmemcmp(V_BSTR(&v) + i, str_ctrl, _countof(str_ctrl) - 1) == 0) {
kc.ctrl = true;
i += _countof(str_ctrl) - 1;
} else if (i + _countof(str_alt) <= n && wmemcmp(V_BSTR(&v) + i, str_alt, _countof(str_alt) - 1) == 0) {
kc.alt = true;
i += _countof(str_alt) - 1;
} else {
kc.key = V_BSTR(&v)[i];
i++;
break;
}
}
if (i < n && V_BSTR(&v)[i] && V_BSTR(&v)[i] != L',' && !_iswspace_l(V_BSTR(&v)[i], m_locale)) {
CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0060: Syntax error in \"%.*ls\" field (\"%.*ls\"). Key sequences must be \"Ctrl+Alt+<key>\" formatted, delimited by commas and/or space.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
return false;
}
seq.push_back(kc);
// Skip delimiter(s) and whitespace.
for (; i < n && V_BSTR(&v)[i] && (V_BSTR(&v)[i] == L',' || _iswspace_l(V_BSTR(&v)[i], m_locale)); i++);
}
return true;
@ -169,7 +223,7 @@ bool ZRCola::DBSource::SelectTranslations(ATL::CComPtr<ADORecordset> &rs) const
// Open it.
if (FAILED(rs->Open(ATL::CComVariant(L"SELECT [komb], [znak] FROM [VRS_ReplChar] WHERE [rang_komb]=1"), ATL::CComVariant(m_db), adOpenStatic, adLockReadOnly, adCmdText))) {
_ftprintf(stderr, wxT("%s: error ZCC0040: Error loading compositions from database. Please make sure the file is ZRCola.zrc compatible.\n"), filename.c_str());
_ftprintf(stderr, wxT("%s: error ZCC0040: Error loading compositions from database. Please make sure the file is ZRCola.zrc compatible.\n"), m_filename.c_str());
LogErrors();
return false;
}
@ -182,20 +236,60 @@ bool ZRCola::DBSource::GetTranslation(const ATL::CComPtr<ADORecordset>& rs, ZRCo
{
wxASSERT_MSG(rs, wxT("recordset is empty"));
CComPtr<ADOFields> flds;
ATL::CComPtr<ADOFields> flds;
wxVERIFY(SUCCEEDED(rs->get_Fields(&flds)));
{
CComPtr<ADOField> f;
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(CComVariant(L"komb"), &f)));
wxCHECK(GetUnicodeString(f, t.str), false);
}
{
CComPtr<ADOField> f;
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(CComVariant(L"znak"), &f)));
wxCHECK(GetUnicodeCharacter(f, t.chr), false);
}
return true;
}
bool ZRCola::DBSource::SelectKeySequences(ATL::CComPtr<ADORecordset> &rs) const
{
// Create a new recordset.
if (rs) rs.Release();
wxCHECK(SUCCEEDED(::CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_ALL, IID_IADORecordset, (LPVOID*)&rs)), false);
// Open it.
if (FAILED(rs->Open(ATL::CComVariant(L"SELECT [Znak], [tipka] FROM [wrd_KeyCodes]"), ATL::CComVariant(m_db), adOpenStatic, adLockReadOnly, adCmdText))) {
_ftprintf(stderr, wxT("%s: error ZCC0050: Error loading key sequences from database. Please make sure the file is ZRCola.zrc compatible.\n"), m_filename.c_str());
LogErrors();
return false;
}
return true;
}
bool ZRCola::DBSource::GetKeySequence(const ATL::CComPtr<ADORecordset>& rs, ZRCola::DBSource::keyseq& ks) const
{
wxASSERT_MSG(rs, wxT("recordset is empty"));
ATL::CComPtr<ADOFields> flds;
wxVERIFY(SUCCEEDED(rs->get_Fields(&flds)));
{
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(CComVariant(L"Znak"), &f)));
wxCHECK(GetUnicodeCharacter(f, ks.chr), false);
}
{
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(CComVariant(L"tipka"), &f)));
wxCHECK(GetKeySequence(f, ks.seq), false);
}
return true;
}

View File

@ -22,6 +22,7 @@
#include <atlbase.h>
#include <adoint.h>
#include <string>
#include <vector>
namespace ZRCola {
@ -40,6 +41,27 @@ namespace ZRCola {
std::wstring str; ///< Decomposed string
};
///
/// Key sequence
///
class keyseq {
public:
///
/// Key code
///
struct keycode {
wchar_t key; ///< Key
bool shift; ///< Shift modifier
bool ctrl; ///< Ctrl modifier
bool alt; ///< Alt modifier
};
public:
wchar_t chr; ///< Character
std::vector<keycode> seq; ///< Key sequence
};
public:
DBSource();
virtual ~DBSource();
@ -93,19 +115,6 @@ namespace ZRCola {
}
///
/// Gets encoded Unicode string from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] str Output string
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetUnicodeString(const CComPtr<ADOField>& f, std::wstring& str) const;
///
/// Gets encoded Unicode character from ZRCola.zrc database
///
@ -116,7 +125,33 @@ namespace ZRCola {
/// - true when successful
/// - false otherwise
///
bool GetUnicodeCharacter(const CComPtr<ADOField>& f, wchar_t& chr) const;
bool GetUnicodeCharacter(const ATL::CComPtr<ADOField>& f, wchar_t& chr) const;
///
/// Gets encoded Unicode string from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] str Output string
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetUnicodeString(const ATL::CComPtr<ADOField>& f, std::wstring& str) const;
///
/// Gets encoded key sequence from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] seq Output sequence
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetKeySequence(const ATL::CComPtr<ADOField>& f, std::vector<keyseq::keycode>& seq) const;
///
@ -143,8 +178,34 @@ namespace ZRCola {
///
bool GetTranslation(const ATL::CComPtr<ADORecordset>& rs, translation& t) const;
///
/// Returns key sequences
///
/// \param[out] rs Recordset with results
///
/// \returns
/// - true when query succeeds
/// - false otherwise
///
bool SelectKeySequences(ATL::CComPtr<ADORecordset>& rs) const;
///
/// Returns key sequence data
///
/// \param[in] rs Recordset with results
/// \param[out] ks Key sequence
///
/// \returns
/// - true when succeeded
/// - false otherwise
///
bool GetKeySequence(const ATL::CComPtr<ADORecordset>& rs, keyseq& ks) const;
protected:
std::basic_string<TCHAR> filename; ///< the database filename
ATL::CComPtr<ADOConnection> m_db; ///< the database
std::basic_string<TCHAR> m_filename; ///< Database filename
ATL::CComPtr<ADOConnection> m_db; ///< Database
_locale_t m_locale; ///< Database locale
};
};

View File

@ -24,18 +24,18 @@
/// Writes translation database to a stream
///
/// \param[in] stream Output stream
/// \param[in] t_db Translation database
/// \param[in] db Translation database
///
/// \returns The stream \p stream
///
inline std::ostream& operator <<(std::ostream& stream, const ZRCola::translation_db &t_db)
inline std::ostream& operator <<(std::ostream& stream, const ZRCola::translation_db &db)
{
assert(t_db.idxComp.size() == t_db.idxDecomp.size());
assert(db.idxComp.size() == db.idxDecomp.size());
unsigned __int32 count;
// Write index count.
std::vector<unsigned __int32>::size_type trans_count = t_db.idxComp.size();
std::vector<unsigned __int32>::size_type trans_count = db.idxComp.size();
#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
// 4G check
if (trans_count > 0xffffffff) {
@ -49,14 +49,14 @@ inline std::ostream& operator <<(std::ostream& stream, const ZRCola::translation
// Write composition index.
if (stream.fail()) return stream;
stream.write((const char*)t_db.idxComp.data(), sizeof(unsigned __int32)*count);
stream.write((const char*)db.idxComp.data(), sizeof(unsigned __int32)*count);
// Write decomposition index.
if (stream.fail()) return stream;
stream.write((const char*)t_db.idxDecomp.data(), sizeof(unsigned __int32)*count);
stream.write((const char*)db.idxDecomp.data(), sizeof(unsigned __int32)*count);
// Write data count.
std::vector<wchar_t>::size_type data_count = t_db.data.size();
std::vector<unsigned __int16>::size_type data_count = db.data.size();
#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
// 4G check
if (data_count > 0xffffffff) {
@ -70,7 +70,63 @@ inline std::ostream& operator <<(std::ostream& stream, const ZRCola::translation
// Write data.
if (stream.fail()) return stream;
stream.write((const char*)t_db.data.data(), sizeof(wchar_t)*count);
stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count);
return stream;
}
///
/// Writes key sequence database to a stream
///
/// \param[in] stream Output stream
/// \param[in] db Key sequence database
///
/// \returns The stream \p stream
///
inline std::ostream& operator <<(std::ostream& stream, const ZRCola::keyseq_db &db)
{
assert(db.idxChr.size() == db.idxKey.size());
unsigned __int32 count;
// Write index count.
std::vector<unsigned __int32>::size_type ks_count = db.idxChr.size();
#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
// 4G check
if (ks_count > 0xffffffff) {
stream.setstate(std::ios_base::failbit);
return stream;
}
#endif
if (stream.fail()) return stream;
count = (unsigned __int32)ks_count;
stream.write((const char*)&count, sizeof(count));
// Write character index.
if (stream.fail()) return stream;
stream.write((const char*)db.idxChr.data(), sizeof(unsigned __int32)*count);
// Write key index.
if (stream.fail()) return stream;
stream.write((const char*)db.idxKey.data(), sizeof(unsigned __int32)*count);
// Write data count.
std::vector<unsigned __int16>::size_type data_count = db.data.size();
#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__)
// 4G check
if (data_count > 0xffffffff) {
stream.setstate(std::ios_base::failbit);
return stream;
}
#endif
if (stream.fail()) return stream;
count = (unsigned __int32)data_count;
stream.write((const char*)&count, sizeof(count));
// Write data.
if (stream.fail()) return stream;
stream.write((const char*)db.data.data(), sizeof(unsigned __int16)*count);
return stream;
}
@ -93,17 +149,42 @@ inline std::ostream& operator <<(std::ostream& stream, const ZRCola::translation
/// The function does not treat \\0 characters as terminators for performance reasons.
/// Therefore \p count_a and \p count_b must represent exact string lengths.
///
static inline int CompareBinary(const wchar_t *str_a, size_t count_a, const wchar_t *str_b, size_t count_b)
static inline int CompareSequence(const wchar_t *str_a, size_t count_a, const wchar_t *str_b, size_t count_b)
{
for (size_t i = 0; ; i++) {
if (i >= count_a && i >= count_b) break;
if (i >= count_a && i >= count_b) return 0;
else if (i >= count_a && i < count_b) return -1;
else if (i < count_a && i >= count_b) return +1;
else if (str_a[i] < str_b[i]) return -1;
else if (str_a[i] > str_b[i]) return +1;
}
}
return 0;
///
/// Compares two key sequences
///
/// \param[in] seq_a First key sequence
/// \param[in] count_a Number of keys in sequence \p seq_a
/// \param[in] seq_b Second key sequence
/// \param[in] count_b Number of keys in sequence \p seq_b
///
/// \returns
/// - <0 when seq_a < seq_b
/// - =0 when seq_a == seq_b
/// - >0 when seq_a > seq_b
///
static inline int CompareSequence(const ZRCola::keyseq_db::keyseq::key_t *seq_a, size_t count_a, const ZRCola::keyseq_db::keyseq::key_t *seq_b, size_t count_b)
{
for (size_t i = 0; ; i++) {
if (i >= count_a && i >= count_b) return 0;
else if (i >= count_a && i < count_b) return -1;
else if (i < count_a && i >= count_b) return +1;
else if (seq_a[i].key < seq_b[i].key ) return -1;
else if (seq_a[i].key > seq_b[i].key ) return +1;
else if (seq_a[i].modifiers < seq_b[i].modifiers) return -1;
else if (seq_a[i].modifiers > seq_b[i].modifiers) return +1;
}
}
@ -122,10 +203,10 @@ static inline int CompareBinary(const wchar_t *str_a, size_t count_a, const wcha
static int __cdecl CompareCompositionIndex(void *data, const void *a, const void *b)
{
const ZRCola::translation_db::translation
&trans_a = (const ZRCola::translation_db::translation&)((const wchar_t*)data)[*(const unsigned __int32*)a],
&trans_b = (const ZRCola::translation_db::translation&)((const wchar_t*)data)[*(const unsigned __int32*)b];
&trans_a = (const ZRCola::translation_db::translation&)((const unsigned __int16*)data)[*(const unsigned __int32*)a],
&trans_b = (const ZRCola::translation_db::translation&)((const unsigned __int16*)data)[*(const unsigned __int32*)b];
int r = CompareBinary(trans_a.str, trans_a.str_len, trans_b.str, trans_b.str_len);
int r = CompareSequence(trans_a.str, trans_a.str_len, trans_b.str, trans_b.str_len);
if (r != 0) return r;
if (trans_a.chr < trans_b.chr) return -1;
@ -150,13 +231,66 @@ static int __cdecl CompareCompositionIndex(void *data, const void *a, const void
static int __cdecl CompareDecompositionIndex(void *data, const void *a, const void *b)
{
const ZRCola::translation_db::translation
&trans_a = (const ZRCola::translation_db::translation&)((const wchar_t*)data)[*(const unsigned __int32*)a],
&trans_b = (const ZRCola::translation_db::translation&)((const wchar_t*)data)[*(const unsigned __int32*)b];
&trans_a = (const ZRCola::translation_db::translation&)((const unsigned __int16*)data)[*(const unsigned __int32*)a],
&trans_b = (const ZRCola::translation_db::translation&)((const unsigned __int16*)data)[*(const unsigned __int32*)b];
if (trans_a.chr < trans_b.chr) return -1;
else if (trans_a.chr > trans_b.chr) return +1;
return CompareBinary(trans_a.str, trans_a.str_len, trans_b.str, trans_b.str_len);
return CompareSequence(trans_a.str, trans_a.str_len, trans_b.str, trans_b.str_len);
}
///
/// Function to use in \c qsort_s for key sequence index sorting
///
/// \param[in] data Pointer to key sequence data
/// \param[in] a Pointer to first key sequence index element
/// \param[in] b Pointer to second key sequence index element
///
/// \returns
/// - <0 when a < b
/// - =0 when a == b
/// - >0 when a > b
///
static int __cdecl CompareKeySequenceChar(void *data, const void *a, const void *b)
{
const ZRCola::keyseq_db::keyseq
&ks_a = (const ZRCola::keyseq_db::keyseq&)((const unsigned __int16*)data)[*(const unsigned __int32*)a],
&ks_b = (const ZRCola::keyseq_db::keyseq&)((const unsigned __int16*)data)[*(const unsigned __int32*)b];
if (ks_a.chr < ks_b.chr) return -1;
else if (ks_a.chr > ks_b.chr) return +1;
return CompareSequence(ks_a.seq, ks_a.seq_len, ks_b.seq, ks_b.seq_len);
}
///
/// Function to use in \c qsort_s for key sequence index sorting
///
/// \param[in] data Pointer to key sequence data
/// \param[in] a Pointer to first key sequence index element
/// \param[in] b Pointer to second key sequence index element
///
/// \returns
/// - <0 when a < b
/// - =0 when a == b
/// - >0 when a > b
///
static int __cdecl CompareKeySequenceKey(void *data, const void *a, const void *b)
{
const ZRCola::keyseq_db::keyseq
&ks_a = (const ZRCola::keyseq_db::keyseq&)((const unsigned __int16*)data)[*(const unsigned __int32*)a],
&ks_b = (const ZRCola::keyseq_db::keyseq&)((const unsigned __int16*)data)[*(const unsigned __int32*)b];
int r = CompareSequence(ks_a.seq, ks_a.seq_len, ks_b.seq, ks_b.seq_len);
if (r != 0) return r;
if (ks_a.chr < ks_b.chr) return -1;
else if (ks_a.chr > ks_b.chr) return +1;
return 0;
}
@ -239,31 +373,30 @@ int _tmain(int argc, _TCHAR *argv[])
// Get translations.
ATL::CComPtr<ADORecordset> rs;
if (src.SelectTranslations(rs)) {
size_t trans_count = src.GetRecordsetCount(rs);
if (trans_count < 0xffffffff) { // 4G check (-1 is reserved for error condition)
size_t count = src.GetRecordsetCount(rs);
if (count < 0xffffffff) { // 4G check (-1 is reserved for error condition)
ZRCola::DBSource::translation trans;
ZRCola::translation_db t_db;
ZRCola::translation_db db;
// Preallocate memory.
t_db.idxComp .reserve(trans_count);
t_db.idxDecomp.reserve(trans_count);
t_db.data .reserve(trans_count*4);
db.idxComp .reserve(count);
db.idxDecomp.reserve(count);
db.data .reserve(count*4);
// Parse translations and build index and data.
while (!ZRCola::DBSource::IsEOF(rs)) {
// Read translation from the database.
if (src.GetTranslation(rs, trans)) {
// Add translation to index and data.
unsigned __int32 ti;
ti = t_db.data.size();
t_db.data.push_back(trans.chr);
unsigned __int32 idx = db.data.size();
db.data.push_back(trans.chr);
std::wstring::size_type n = trans.str.length();
wxASSERT_MSG(n <= 0xffff, wxT("transformation string too long"));
t_db.data.push_back((wchar_t)n);
db.data.push_back((unsigned __int16)n);
for (std::wstring::size_type i = 0; i < n; i++)
t_db.data.push_back(trans.str[i]);
t_db.idxComp .push_back(ti);
t_db.idxDecomp.push_back(ti);
db.data.push_back(trans.str[i]);
db.idxComp .push_back(idx);
db.idxDecomp.push_back(idx);
} else
has_errors = true;
@ -271,11 +404,11 @@ int _tmain(int argc, _TCHAR *argv[])
}
// Sort indices.
qsort_s(t_db.idxComp .data(), trans_count, sizeof(unsigned __int32), CompareCompositionIndex , t_db.data.data());
qsort_s(t_db.idxDecomp.data(), trans_count, sizeof(unsigned __int32), CompareDecompositionIndex, t_db.data.data());
qsort_s(db.idxComp .data(), count, sizeof(unsigned __int32), CompareCompositionIndex , db.data.data());
qsort_s(db.idxDecomp.data(), count, sizeof(unsigned __int32), CompareDecompositionIndex, db.data.data());
// Write translations to file.
dst << ZRCola::translation_rec(t_db);
dst << ZRCola::translation_rec(db);
} else {
_ftprintf(stderr, wxT("%s: error ZCC0004: Error getting translation count from database or too many translations.\n"), (LPCTSTR)filenameIn.c_str());
has_errors = true;
@ -286,10 +419,67 @@ int _tmain(int argc, _TCHAR *argv[])
}
}
{
// Get key sequences.
ATL::CComPtr<ADORecordset> rs;
if (src.SelectKeySequences(rs)) {
size_t count = src.GetRecordsetCount(rs);
if (count < 0xffffffff) { // 4G check (-1 is reserved for error condition)
ZRCola::DBSource::keyseq ks;
ZRCola::keyseq_db db;
// Preallocate memory.
db.idxChr.reserve(count);
db.idxKey.reserve(count);
db.data .reserve(count*4);
// Parse translations and build index and data.
while (!ZRCola::DBSource::IsEOF(rs)) {
// Read translation from the database.
if (src.GetKeySequence(rs, ks)) {
// Add translation to index and data.
unsigned __int32 idx = db.data.size();
db.data.push_back(ks.chr);
std::vector<ZRCola::DBSource::keyseq::keycode>::size_type n = ks.seq.size();
wxASSERT_MSG(n <= 0xffff, wxT("key sequence too long"));
db.data.push_back((unsigned __int16)n);
for (std::vector<ZRCola::DBSource::keyseq::keycode>::size_type i = 0; i < n; i++) {
const ZRCola::DBSource::keyseq::keycode &kc = ks.seq[i];
db.data.push_back(kc.key);
db.data.push_back(
(kc.shift ? ZRCola::keyseq_db::keyseq::SHIFT : 0) |
(kc.ctrl ? ZRCola::keyseq_db::keyseq::CTRL : 0) |
(kc.alt ? ZRCola::keyseq_db::keyseq::ALT : 0));
}
db.idxChr.push_back(idx);
db.idxKey.push_back(idx);
} else
has_errors = true;
wxVERIFY(SUCCEEDED(rs->MoveNext()));
}
// Sort indices.
qsort_s(db.idxChr.data(), count, sizeof(unsigned __int32), CompareKeySequenceChar, db.data.data());
qsort_s(db.idxKey.data(), count, sizeof(unsigned __int32), CompareKeySequenceKey , db.data.data());
// Write translations to file.
dst << ZRCola::keyseq_rec(db);
} else {
_ftprintf(stderr, wxT("%s: error ZCC0006: Error getting key sequence count from database or too many key sequences.\n"), (LPCTSTR)filenameIn.c_str());
has_errors = true;
}
} else {
_ftprintf(stderr, wxT("%s: error ZCC0005: Error getting key sequences from database. Please make sure the file is ZRCola.zrc compatible.\n"), (LPCTSTR)filenameIn.c_str());
has_errors = true;
}
}
stdex::idrec::close<ZRCola::recordid_t, ZRCola::recordsize_t, ZRCOLA_RECORD_ALIGN>(dst, dst_start);
if (dst.fail()) {
_ftprintf(stderr, wxT("%s: error ZCC0005: Writing to output file failed.\n"), (LPCTSTR)filenameOut.c_str());
_ftprintf(stderr, wxT("%s: error ZCC0007: Writing to output file failed.\n"), (LPCTSTR)filenameOut.c_str());
has_errors = true;
}

View File

@ -23,6 +23,7 @@
#include "dbsource.h"
#include <zrcola/translate.h>
#include <zrcolaui/keyboard.h>
#include <wx/app.h>
#include <wx/cmdline.h>

View File

@ -10,6 +10,7 @@
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>LIBZRCOLAUI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\stdex\include;..\..\libZRCola\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -19,6 +19,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\keyboard.cpp" />
<ClCompile Include="..\src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
@ -28,6 +29,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\zrcolaui\common.h" />
<ClInclude Include="..\include\zrcolaui\keyboard.h" />
<ClInclude Include="..\src\stdafx.h" />
</ItemGroup>
<ItemGroup>

View File

@ -18,6 +18,9 @@
<ClCompile Include="..\src\stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\keyboard.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\stdafx.h">
@ -26,6 +29,9 @@
<ClInclude Include="..\include\zrcolaui\common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\zrcolaui\keyboard.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\res\libZRColaUI.rc">

View File

@ -24,16 +24,8 @@
/// Public function calling convention
///
#ifdef LIBZRCOLAUI
#define ZRCOLAUI_API __declspec(dllexport)
#define ZRCOLAUI_API __declspec(dllexport)
#else
#define ZRCOLAUI_API __declspec(dllimport)
#define ZRCOLAUI_API __declspec(dllimport)
#endif
#define ZRCOLA_NOVTABLE __declspec(novtable)
#pragma warning(push)
#pragma warning(disable: 4251)
namespace ZRCola {
};
#pragma warning(pop)

View File

@ -0,0 +1,113 @@
/*
Copyright 2015-2016 Amebis
This file is part of ZRCola.
ZRCola is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ZRCola is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ZRCola. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common.h"
#include <zrcola/common.h>
#include <stdex/idrec.h>
#include <istream>
#include <vector>
#pragma warning(push)
#pragma warning(disable: 4251)
namespace ZRCola {
///
/// Key sequence database
///
class ZRCOLAUI_API keyseq_db {
public:
#pragma pack(push)
#pragma pack(2)
#pragma warning(push)
#pragma warning(disable: 4200)
///
/// Key sequence data
///
struct keyseq {
enum modifiers_t {
SHIFT = 1<<0, ///< SHIFT key was pressed
CTRL = 1<<1, ///< CTRL key was pressed
ALT = 1<<2, ///< ALT key was pressed
};
wchar_t chr; ///< Character
unsigned __int16 seq_len; ///< \c seq length
struct key_t {
wchar_t key; ///< Key
unsigned __int16 modifiers; ///< Modifiers (bitwise combination of SHIFT, CTRL and ALT)
} seq[]; ///< Key sequence
};
#pragma warning(pop)
#pragma pack(pop)
std::vector<unsigned __int32> idxChr; ///< Character index
std::vector<unsigned __int32> idxKey; ///< Key index
std::vector<unsigned __int16> data; ///< Key sequences data
};
typedef ZRCOLAUI_API stdex::idrec::record<keyseq_db, recordid_t, recordsize_t, ZRCOLA_RECORD_ALIGN> keyseq_rec;
};
const ZRCola::recordid_t stdex::idrec::record<ZRCola::keyseq_db, ZRCola::recordid_t, ZRCola::recordsize_t, ZRCOLA_RECORD_ALIGN>::id = *(ZRCola::recordid_t*)"KEY";
///
/// Reads key sequence database from a stream
///
/// \param[in] stream Input stream
/// \param[out] db Key sequence database
///
/// \returns The stream \p stream
///
inline std::istream& operator >>(_In_ std::istream& stream, _Out_ ZRCola::keyseq_db &db)
{
unsigned __int32 count;
// Read index count.
stream.read((char*)&count, sizeof(count));
if (!stream.good()) return stream;
// Read character index.
db.idxChr.resize(count);
stream.read((char*)db.idxChr.data(), sizeof(unsigned __int32)*count);
if (!stream.good()) return stream;
// Read key index.
db.idxKey.resize(count);
stream.read((char*)db.idxKey.data(), sizeof(unsigned __int32)*count);
if (!stream.good()) return stream;
// Read data count.
stream.read((char*)&count, sizeof(count));
if (!stream.good()) return stream;
// Read data.
db.data.resize(count);
stream.read((char*)db.data.data(), sizeof(unsigned __int16)*count);
return stream;
}
#pragma warning(pop)

View File

@ -0,0 +1,20 @@
/*
Copyright 2015-2016 Amebis
This file is part of ZRCola.
ZRCola is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ZRCola is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ZRCola. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"

View File

@ -20,3 +20,4 @@
#pragma once
#include "../../../include/zrcola.h"
#include "../include/zrcolaui/keyboard.h"

Binary file not shown.