Support for dynamic keyboard shortcuts added
This commit is contained in:
parent
f3c0e83d04
commit
5398ccbd5e
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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,45 +152,64 @@ 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;
|
||||
|
||||
// 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 <= 0 && 4 < i) {
|
||||
}
|
||||
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 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));
|
||||
_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;
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "dbsource.h"
|
||||
|
||||
#include <zrcola/translate.h>
|
||||
#include <zrcolaui/keyboard.h>
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/cmdline.h>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>LIBZRCOLAUI;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\stdex\include;..\..\libZRCola\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -29,11 +29,3 @@
|
||||
#define ZRCOLAUI_API __declspec(dllimport)
|
||||
#endif
|
||||
#define ZRCOLA_NOVTABLE __declspec(novtable)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4251)
|
||||
|
||||
|
||||
namespace ZRCola {
|
||||
};
|
||||
|
||||
#pragma warning(pop)
|
||||
|
113
lib/libZRColaUI/include/zrcolaui/keyboard.h
Normal file
113
lib/libZRColaUI/include/zrcolaui/keyboard.h
Normal 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)
|
20
lib/libZRColaUI/src/keyboard.cpp
Normal file
20
lib/libZRColaUI/src/keyboard.cpp
Normal 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"
|
@ -20,3 +20,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../include/zrcola.h"
|
||||
#include "../include/zrcolaui/keyboard.h"
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user