/* Copyright 2015-2017 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 . */ #include "stdafx.h" ////////////////////////////////////////////////////////////////////////// // wxZRColaKeyHandler ////////////////////////////////////////////////////////////////////////// wxZRColaKeyHandler::wxZRColaKeyHandler() : m_is_insert(false), wxEvtHandler() { } bool wxZRColaKeyHandler::ProcessEvent(wxEvent& event) { if (event.GetEventType() == wxEVT_KEY_DOWN) { // The character event occured. wxKeyEvent &e = (wxKeyEvent&)event; if (e.GetKeyCode() == WXK_INSERT) { // Insert key has been pressed. m_is_insert = true; wxFrame *pFrame = wxDynamicCast(dynamic_cast(wxTheApp)->m_mainWnd, wxFrame); if (pFrame && pFrame->GetStatusBar()) pFrame->SetStatusText(_("INS key is pressed. Type the Unicode code of desired character now (up to four hexadecimal digits: 0-9, A-F), then release INS.")); } else if (m_is_insert) { wxChar chr = e.GetUnicodeKey(); if (!chr) { int key = e.GetKeyCode(); if (WXK_NUMPAD0 <= key && key <= WXK_NUMPAD9) chr = '0' + (key - WXK_NUMPAD0); } wxFrame *pFrame = wxDynamicCast(dynamic_cast(wxTheApp)->m_mainWnd, wxFrame); if (('0' <= chr && chr <= '9' || 'A' <= chr && chr <= 'F') && m_insert_seq.size() < 4) { // A hex-digit pressed. Save it. m_insert_seq.push_back((char)chr); if (pFrame && pFrame->GetStatusBar()) pFrame->SetStatusText(wxString::Format(wxT("U+%s"), (const wxStringCharType*)wxString(m_insert_seq.data(), m_insert_seq.size()))); event.StopPropagation(); return true; } else { // Not a hex-digit. m_is_insert = false; m_insert_seq.clear(); if (pFrame && pFrame->GetStatusBar()) pFrame->SetStatusText(wxEmptyString); } } else if ((e.GetUnicodeKey() || !e.HasAnyModifiers()) #if defined(__WXMSW__) && ::GetKeyState(VK_RMENU) >= 0 #endif ) { auto app = dynamic_cast(wxTheApp); ZRCola::keyseq_db::indexKey::size_type start; bool found; wxFrame *pFrame = wxDynamicCast(app->m_mainWnd, wxFrame); { // Parse key event and save it at the end of the key sequence. ZRCola::keyseq_db::keyseq::key_t key; key.key = e.GetRawKeyCode(); #if defined(__WXMSW__) // Translate from local keyboard to scan code. key.key = ::MapVirtualKey(key.key, MAPVK_VK_TO_VSC); // Translate from scan code to U.S. Keyboard. static const HKL s_hkl = ::LoadKeyboardLayout(_T("00000409"), 0); key.key = ::MapVirtualKeyEx(key.key, MAPVK_VSC_TO_VK, s_hkl); #endif 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); auto 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 = app->m_ks_db.idxKey.find(*ks, start); delete ks; } if (found) { // The exact key sequence found. const ZRCola::keyseq_db::keyseq &ks = app->m_ks_db.idxKey[start]; m_seq.clear(); 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); // Event is fully processed now. event.StopPropagation(); return true; } } else if (start < app->m_ks_db.idxKey.size() && ZRCola::keyseq_db::keyseq::CompareSequence(m_seq.data(), m_seq.size(), app->m_ks_db.idxKey[start].seq, std::min(app->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); } } } else if (event.GetEventType() == wxEVT_KEY_UP) { wxKeyEvent &e = (wxKeyEvent&)event; if (m_is_insert && e.GetKeyCode() == WXK_INSERT) { // Insert key has been depressed. wxFrame *pFrame = wxDynamicCast(dynamic_cast(wxTheApp)->m_mainWnd, wxFrame); if (pFrame && pFrame->GetStatusBar()) pFrame->SetStatusText(wxEmptyString); auto count = m_insert_seq.size(); if (count) { // Zero terminate sequence and parse the Unicode value. m_insert_seq.push_back(0); wchar_t chr = strtoul(m_insert_seq.data(), NULL, 16); if (chr) { wxObject *obj = event.GetEventObject(); if (obj && obj->IsKindOf(wxCLASSINFO(wxTextCtrl))) { // Push text to source control. ((wxTextCtrl*)obj)->WriteText(chr); } } m_insert_seq.clear(); } m_is_insert = false; event.StopPropagation(); return true; } } return wxEvtHandler::ProcessEvent(event); }