Compare commits

..

9 Commits

Author SHA1 Message Date
Simon Rozman
cd2c20fc06 Version set to 2.0-alpha3. 2016-04-08 09:22:10 +02:00
Simon Rozman
ac772671cc Publish target split into PublishPre and Publish 2016-04-08 09:21:53 +02:00
Simon Rozman
acfe980705 Non-working OEM key sequences issue fixed
resolves #5
2016-04-07 14:52:45 +02:00
Simon Rozman
426b7a6227 Keyboard sequence monitoring upgraded not to react on modifier keys, canceling multi-key sequences when non-first key modifier pressed 2016-04-07 14:49:28 +02:00
Simon Rozman
834743c7dd Cleanup 2016-04-07 13:10:54 +02:00
Simon Rozman
c8628ef4eb Key sequence import fixed (resolves #7) 2016-04-07 12:53:19 +02:00
Simon Rozman
4f52304fe9 Advertised shortcuts disabled (closes #4) 2016-04-07 10:50:31 +02:00
Simon Rozman
eef80067bb Language setting moved from HKCU (per-user) to HKLM (global) 2016-04-07 09:41:29 +02:00
Simon Rozman
9240288245 Generic module names replaced 2016-04-06 14:14:35 +02:00
25 changed files with 197 additions and 103 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -317,6 +317,7 @@ s$(MSIBUILD_LENGTH_ID) l0
Property Property
ARPPRODUCTICON iconZRCola.ico
ALLUSERS 1
DISABLEADVTSHORTCUTS 1
INSTALLLEVEL 3
InstallMode Typical
SecureCustomProperties OLDPRODUCTFOUND;NEWPRODUCTFOUND
@@ -346,7 +347,7 @@ regDatabasePath 2 SOFTWARE\Amebis\ZRCola DatabasePath [ZRCOLADATADIR] compDataba
Registry Root Key Name Value Component_
s$(MSIBUILD_LENGTH_ID) i2 l255 L255 L0 s$(MSIBUILD_LENGTH_ID)
1252 Registry Registry
regLanguage 1 SOFTWARE\Amebis\ZRCola Language #60 compLanguage
regLanguage 2 SOFTWARE\Amebis\ZRCola Language #60 compLanguage
<<NOKEEP
"De.$(PLAT).$(CFG).Registry-2.idt" : "En.$(PLAT).$(CFG).Registry-2.idtx" "..\locale\de_DE.po"

View File

@@ -82,6 +82,7 @@ Setup \
SetupDebug \
Register \
Unregister \
PublishPre \
Publish :: "MSI\MSIBuild\Version\Version.mak"
$(MAKE) /f "Makefile" /$(MAKEFLAGS) HAS_VERSION=1 $@
@@ -183,12 +184,15 @@ RegisterShortcuts :: \
UnregisterShortcuts ::
-if exist "$(PROGRAMDATA)\Microsoft\Windows\Start Menu\Programs\ZRCola" rd /s /q "$(PROGRAMDATA)\Microsoft\Windows\Start Menu\Programs\ZRCola"
Publish :: \
PublishPre :: \
"$(PUBLISH_PACKAGE_DIR)" \
$(REDIST_EN_WIN32) \
$(REDIST_EN_X64) \
$(REDIST_SL_WIN32) \
$(REDIST_SL_X64) \
$(REDIST_SL_X64)
Publish :: \
PublishPre \
"$(PUBLISH_DIR)\catalog-0000.xml"

View File

@@ -35,3 +35,7 @@
#include <vector>
#include <stdex/idrec.h>
#if defined(__WXMSW__)
#include <Msi.h>
#endif

View File

@@ -18,6 +18,9 @@
*/
#include "stdafx.h"
#if defined(__WXMSW__)
#pragma comment(lib, "msi.lib")
#endif
//////////////////////////////////////////////////////////////////////////
@@ -34,6 +37,14 @@ ZRColaApp::ZRColaApp() : wxApp()
bool ZRColaApp::OnInit()
{
#if defined(__WXMSW__)
// To compensate migration to non-advertised shortcut, do the Microsoft Installer's feature completeness check manually.
// If execution got this far in the first place (EXE and dependent DLLs are present and loadable).
// Furthermore, this increments program usage counter.
if (::MsiQueryFeatureState(_T(ZRCOLA_VERSION_GUID), _T("featZRCola")) != INSTALLSTATE_UNKNOWN)
::MsiUseFeature(_T(ZRCOLA_VERSION_GUID), _T("featZRCola"));
#endif
wxConfigBase *cfgPrev = wxConfigBase::Set(new wxConfig(wxT(ZRCOLA_CFG_APPLICATION), wxT(ZRCOLA_CFG_VENDOR)));
if (cfgPrev) wxDELETE(cfgPrev);

View File

@@ -54,62 +54,64 @@ bool wxZRColaKeyHandler::ProcessEvent(wxEvent& event)
{
if (event.GetEventType() == wxEVT_KEY_DOWN) {
// The character event occured.
ZRCola::keyseq_db::indexKey::size_type start, end;
bool found;
wxFrame *pFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
wxKeyEvent &e = (wxKeyEvent&)event;
if (e.GetUnicodeKey() || !e.HasAnyModifiers()) {
ZRCola::keyseq_db::indexKey::size_type start, end;
bool found;
wxFrame *pFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
{
// Parse key event and save it at the end of the key sequence.
wxKeyEvent &e = (wxKeyEvent&)event;
ZRCola::keyseq_db::keyseq::key_t key;
key.key = e.GetKeyCode(); //wxToupper(e.m_uniChar);
key.modifiers =
(e.ShiftDown() ? ZRCola::keyseq_db::keyseq::SHIFT : 0) |
(e.ControlDown() ? ZRCola::keyseq_db::keyseq::CTRL : 0) |
(e.AltDown() ? ZRCola::keyseq_db::keyseq::ALT : 0);
m_seq.push_back(key);
{
// Parse key event and save it at the end of the key sequence.
ZRCola::keyseq_db::keyseq::key_t key;
key.key = e.GetRawKeyCode();
key.modifiers =
(e.ShiftDown() ? ZRCola::keyseq_db::keyseq::SHIFT : 0) |
(e.ControlDown() ? ZRCola::keyseq_db::keyseq::CTRL : 0) |
(e.AltDown() ? ZRCola::keyseq_db::keyseq::ALT : 0);
m_seq.push_back(key);
std::vector<ZRCola::keyseq_db::keyseq::key_t>::size_type n = m_seq.size();
ZRCola::keyseq_db::keyseq *ks = (ZRCola::keyseq_db::keyseq*)new char[sizeof(ZRCola::keyseq_db::keyseq) + sizeof(ZRCola::keyseq_db::keyseq::key_t)*n];
ks->chr = 0;
ks->seq_len = n;
memcpy(ks->seq, m_seq.data(), sizeof(ZRCola::keyseq_db::keyseq::key_t)*n);
found = m_ks_db.idxKey.find(*ks, start, end);
delete ks;
}
std::vector<ZRCola::keyseq_db::keyseq::key_t>::size_type n = m_seq.size();
ZRCola::keyseq_db::keyseq *ks = (ZRCola::keyseq_db::keyseq*)new char[sizeof(ZRCola::keyseq_db::keyseq) + sizeof(ZRCola::keyseq_db::keyseq::key_t)*n];
ks->chr = 0;
ks->seq_len = n;
memcpy(ks->seq, m_seq.data(), sizeof(ZRCola::keyseq_db::keyseq::key_t)*n);
found = m_ks_db.idxKey.find(*ks, start, end);
delete ks;
}
if (found) {
// The exact key sequence found.
const ZRCola::keyseq_db::keyseq &ks = m_ks_db.idxKey[start];
m_seq.clear();
if (found) {
// The exact key sequence found.
const ZRCola::keyseq_db::keyseq &ks = m_ks_db.idxKey[start];
m_seq.clear();
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(wxEmptyString);
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(wxEmptyString);
wxObject *obj = event.GetEventObject();
if (obj && obj->IsKindOf(wxCLASSINFO(wxTextCtrl))) {
// Push text to source control.
((wxTextCtrl*)obj)->WriteText(ks.chr);
wxObject *obj = event.GetEventObject();
if (obj && obj->IsKindOf(wxCLASSINFO(wxTextCtrl))) {
// Push text to source control.
((wxTextCtrl*)obj)->WriteText(ks.chr);
// Event is fully processed now.
event.StopPropagation();
return true;
}
} else if (start < m_ks_db.idxKey.size() &&
ZRCola::keyseq_db::keyseq::CompareSequence(m_seq.data(), m_seq.size(), m_ks_db.idxKey[start].seq, std::min<unsigned __int16>(m_ks_db.idxKey[start].seq_len, m_seq.size())) == 0)
{
// The sequence is a partial match. Continue watching.
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(ZRCola::keyseq_db::GetSequenceAsText(m_seq.data(), m_seq.size()));
// Event is fully processed now.
event.StopPropagation();
return true;
} else {
// The key sequence has no future chance to match. Start all over again.
m_seq.clear();
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(wxEmptyString);
}
} else if (start < m_ks_db.idxKey.size() &&
ZRCola::keyseq_db::keyseq::CompareSequence(m_seq.data(), m_seq.size(), m_ks_db.idxKey[start].seq, std::min<unsigned __int16>(m_ks_db.idxKey[start].seq_len, m_seq.size())) == 0)
{
// The sequence is a partial match. Continue watching.
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(ZRCola::keyseq_db::GetSequenceAsText(m_seq.data(), m_seq.size()));
event.StopPropagation();
return true;
} else {
// The key sequence has no future chance to match. Start all over again.
m_seq.clear();
if (pFrame && pFrame->GetStatusBar())
pFrame->SetStatusText(wxEmptyString);
}
}

View File

@@ -99,15 +99,43 @@ void ZRCola::DBSource::LogErrors() const
}
bool ZRCola::DBSource::GetValue(const ATL::CComPtr<ADOField>& f, bool& val) const
{
wxASSERT_MSG(f, wxT("field is empty"));
ATL::CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
wxCHECK(SUCCEEDED(v.ChangeType(VT_BOOL)), false);
val = V_BOOL(&v) ? true : false;
return true;
}
bool ZRCola::DBSource::GetValue(const ATL::CComPtr<ADOField>& f, int& val) const
{
wxASSERT_MSG(f, wxT("field is empty"));
ATL::CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
wxCHECK(SUCCEEDED(v.ChangeType(VT_I4)), false);
val = V_I4(&v);
return true;
}
bool ZRCola::DBSource::GetUnicodeCharacter(const ATL::CComPtr<ADOField>& f, wchar_t& chr) const
{
wxASSERT_MSG(f, wxT("field is empty"));
ATL::CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
wxCHECK(SUCCEEDED(v.ChangeType(VT_BSTR)), false);
// 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++) {
@@ -136,9 +164,9 @@ bool ZRCola::DBSource::GetUnicodeString(const ATL::CComPtr<ADOField>& f, std::ws
ATL::CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
wxCHECK(SUCCEEDED(v.ChangeType(VT_BSTR)), false);
// Parse the field. Must be "xxxx+xxxx+xxxx..." sequence.
wxVERIFY(SUCCEEDED(v.ChangeType(VT_BSTR)));
str.clear();
for (UINT i = 0, n = ::SysStringLen(V_BSTR(&v)); i < n && V_BSTR(&v)[i];) {
// Parse Unicode code.
@@ -165,58 +193,48 @@ bool ZRCola::DBSource::GetUnicodeString(const ATL::CComPtr<ADOField>& f, std::ws
}
bool ZRCola::DBSource::GetKeySequence(const ATL::CComPtr<ADOField>& f, std::vector<keyseq::keycode>& seq) const
bool ZRCola::DBSource::GetKeyCode(const ATL::CComPtr<ADOField>& f, ZRCola::DBSource::keyseq::keycode& kc) const
{
wxASSERT_MSG(f, wxT("field is empty"));
ATL::CComVariant v;
wxVERIFY(SUCCEEDED(f->get_Value(&v)));
wxVERIFY(SUCCEEDED(v.ChangeType(VT_BSTR)));
wxCHECK(SUCCEEDED(v.ChangeType(VT_BSTR)), false);
// Convert to uppercase.
_wcsupr_l(V_BSTR(&v), m_locale);
// Parse the field. Must be comma delimited sequence of key codes.
seq.clear();
// Parse the field.
memset(&kc, 0, sizeof(kc));
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;
// Parse key code.
if (i) {
// Check for "+" separator.
if (V_BSTR(&v)[i] != L'+') {
ATL::CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0070: Syntax error in \"%.*ls\" field (\"%.*ls\"). Key codes must be \"Ctrl+Alt+<key>\" formatted.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
}
i++;
if (i >= n || !V_BSTR(&v)[i]) {
ATL::CComBSTR fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname)));
_ftprintf(stderr, wxT("%s: error ZCC0071: Syntax error in \"%.*ls\" field (\"%.*ls\"). Trailing separator \"+\" found.\n"), m_filename.c_str(), fieldname.Length(), (BSTR)fieldname, n, V_BSTR(&v));
}
}
if (i < n && V_BSTR(&v)[i] && V_BSTR(&v)[i] != L',' && !_iswspace_l(V_BSTR(&v)[i], m_locale)) {
ATL::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;
}
if (seq.size() > 0xffff) {
_ftprintf(stderr, wxT("%s: warning ZCC0061: Key sequence \"%.*ls...\" too long. Ignored.\n"), (LPCTSTR)m_filename.c_str(), std::min<UINT>(n, 20), 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++);
}
if (seq.empty()) {
_ftprintf(stderr, wxT("%s: warning ZCC0062: Empty key sequence. Ignored.\n"), (LPCTSTR)m_filename.c_str());
return false;
static const wchar_t str_shift[] = L"SHIFT", str_ctrl[] = L"CTRL", str_alt[] = L"ALT";
if (i + _countof(str_shift) - 1 <= 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) - 1 <= 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) - 1 <= 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++;
}
}
return true;
@@ -270,7 +288,7 @@ bool ZRCola::DBSource::SelectKeySequences(ATL::CComPtr<ADORecordset> &rs) const
wxCHECK(SUCCEEDED(::CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_ALL, IID_IADORecordset, (LPVOID*)&rs)), false);
// Open it.
if (FAILED(rs->Open(ATL::CComVariant(L"SELECT DISTINCT [Znak], [tipka] FROM [wrd_KeyCodes]"), ATL::CComVariant(m_db), adOpenStatic, adLockReadOnly, adCmdText))) {
if (FAILED(rs->Open(ATL::CComVariant(L"SELECT DISTINCT [VRS_KeyCodes].[Znak], [VRS_CharGroup].[Name] AS [CharGroup], [VRS_KeyCodes].[KeyCode], [VRS_KeyCodes].[Shift] FROM [VRS_KeyCodes] LEFT JOIN [VRS_CharGroup] ON [VRS_CharGroup].[CharGroup]=[VRS_KeyCodes].[CharGroup]"), 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;
@@ -293,10 +311,38 @@ bool ZRCola::DBSource::GetKeySequence(const ATL::CComPtr<ADORecordset>& rs, ZRCo
wxCHECK(GetUnicodeCharacter(f, ks.chr), false);
}
keyseq::keycode kc1;
{
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(ATL::CComVariant(L"tipka"), &f)));
wxCHECK(GetKeySequence(f, ks.seq), false);
wxVERIFY(SUCCEEDED(flds->get_Item(ATL::CComVariant(L"CharGroup"), &f)));
wxCHECK(GetKeyCode(f, kc1), false);
}
int keycode;
{
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(ATL::CComVariant(L"KeyCode"), &f)));
wxCHECK(GetValue(f, keycode), false);
}
bool shift;
{
ATL::CComPtr<ADOField> f;
wxVERIFY(SUCCEEDED(flds->get_Item(ATL::CComVariant(L"Shift"), &f)));
wxCHECK(GetValue(f, shift), false);
}
ks.seq.clear();
if (kc1.key) {
// First key in the sequence is complete.
ks.seq.push_back(kc1);
keyseq::keycode kc2 = { keycode, shift };
ks.seq.push_back(kc2);
} else {
// First key in the sequence is only modifier(s).
kc1.key = keycode;
if (shift) kc1.shift = true;
ks.seq.push_back(kc1);
}
return true;

View File

@@ -115,6 +115,32 @@ namespace ZRCola {
}
///
/// Gets boolean from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] val Output boolean value
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetValue(const ATL::CComPtr<ADOField>& f, bool& val) const;
///
/// Gets integer from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] val Output integer value
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetValue(const ATL::CComPtr<ADOField>& f, int& val) const;
///
/// Gets encoded Unicode character from ZRCola.zrc database
///
@@ -142,16 +168,16 @@ namespace ZRCola {
///
/// Gets encoded key sequence from ZRCola.zrc database
/// Gets encoded key from ZRCola.zrc database
///
/// \param[in] f Data field
/// \param[out] seq Output sequence
/// \param[in] f Data field
/// \param[out] kc Output key code
///
/// \returns
/// - true when successful
/// - false otherwise
///
bool GetKeySequence(const ATL::CComPtr<ADOField>& f, std::vector<keyseq::keycode>& seq) const;
bool GetKeyCode(const ATL::CComPtr<ADOField>& f, keyseq::keycode& kc) const;
///

View File

@@ -23,7 +23,7 @@
// Product version as a single DWORD
// Note: Used for version comparison within C/C++ code.
//
#define ZRCOLA_VERSION 0x01ff0200
#define ZRCOLA_VERSION 0x01ff0300
//
// Product version by components
@@ -33,26 +33,26 @@
//
#define ZRCOLA_VERSION_MAJ 1
#define ZRCOLA_VERSION_MIN 255
#define ZRCOLA_VERSION_REV 2
#define ZRCOLA_VERSION_REV 3
#define ZRCOLA_VERSION_BUILD 0
//
// Human readable product version and build year for UI
//
#define ZRCOLA_VERSION_STR "2.0-alpha2"
#define ZRCOLA_VERSION_STR "2.0-alpha3"
#define ZRCOLA_BUILD_YEAR_STR "2016"
//
// Numerical version presentation for ProductVersion propery in
// MSI packages (syntax: N.N[.N[.N]])
//
#define ZRCOLA_VERSION_INST "1.255.2"
#define ZRCOLA_VERSION_INST "1.255.3"
//
// The product code for ProductCode property in MSI packages
// Replace with new on every version change, regardless how minor it is.
//
#define ZRCOLA_VERSION_GUID "{221AC7C3-020F-4A9B-8005-D49F8B5FE815}"
#define ZRCOLA_VERSION_GUID "{8553943A-9CD0-4639-98CC-0A57A84A7765}"
//
// The product vendor and application name for configuration keeping.

Binary file not shown.