///////////////////////////////////////////////////////////////////////////// // Name: hotkeymanager.cpp // Author: Cesar Mauri Loba (cesar at crea-si dot com) // Copyright: (C) 2010-16 Cesar Mauri Loba - CREA Software Systems // // This program 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. // // This program 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 this program. If not, see . ///////////////////////////////////////////////////////////////////////////// #include "hotkeymanager.h" #include #include "eviacamdefs.h" #include "eviacamapp.h" #include "viacamcontroller.h" #include "pointeraction.h" #include "simplelog.h" namespace eviacam { // // Define the available key commands // class HotKeyCommandEnable : public HotKey { public: HotKeyCommandEnable(int id) : HotKey(id, _T("hotKeyEnable"), _("Enable eViacam"), KeyboardCode::FromWXK(WXK_F11)) {} void Command() override { wxGetApp().GetController().SetEnabled(!wxGetApp().GetController().GetEnabled(), true); } }; class HotKeyCommandCenterPointer : public HotKey { public: HotKeyCommandCenterPointer(int id) : HotKey(id, _T("hotKeyCenterPointer"), _("Center the pointer"), KeyboardCode::FromWXK(WXK_F10)) {} void Command() override { wxGetApp().GetController().GetPointerAction().CenterPointer(); } }; class HotKeyCommandWorkspace : public HotKey { public: HotKeyCommandWorkspace(int id) : HotKey(id, _T("hotKeyWorkspace"), _("Enable workspace limit"), KeyboardCode::FromWXK(WXK_F9)) {} void Command() override { wxGetApp().GetController().GetPointerAction().SetRestrictedWorkingArea( !wxGetApp().GetController().GetPointerAction().GetRestrictedWorkingArea()); } }; class HotKeyCommandIncreaseX : public HotKey { public: HotKeyCommandIncreaseX(int id) : HotKey(id, ("hotKeyIncreaseX"), _("Increase the X axis speed"), KeyboardCode::FromWXK(WXK_RIGHT)) {} void Command() override { wxGetApp().GetController().GetPointerAction().SetXSpeed(wxGetApp().GetController().GetPointerAction().GetXSpeed()+1); } }; class HotKeyCommandIncreaseY : public HotKey { public: HotKeyCommandIncreaseY(int id) : HotKey(id, _T("hotKeyIncreaseY"), _("Increase the Y axis speed"), KeyboardCode::FromWXK(WXK_UP)) {} void Command() override { wxGetApp().GetController().GetPointerAction().SetYSpeed( wxGetApp().GetController().GetPointerAction().GetYSpeed()+1); } }; class HotKeyCommandDecreaseX : public HotKey { public: HotKeyCommandDecreaseX(int id) : HotKey(id, _T("hotKeyDecreaseX"), _("Decrease the X axis speed"), KeyboardCode::FromWXK(WXK_LEFT)) {} void Command() override { wxGetApp().GetController().GetPointerAction().SetXSpeed( wxGetApp().GetController().GetPointerAction().GetXSpeed()-1); } }; class HotKeyCommandDecreaseY : public HotKey { public: HotKeyCommandDecreaseY(int id) : HotKey(id, _T("hotKeyDecreaseY"), _("Decrease the Y axis speed"), KeyboardCode::FromWXK(WXK_DOWN)) {} void Command() override { wxGetApp().GetController().GetPointerAction().SetYSpeed( wxGetApp().GetController().GetPointerAction().GetYSpeed()-1); } }; static const KeyboardCode g_banned_hotkeys[]= { #if defined(__WXMSW__) KeyboardCode(VK_SHIFT), KeyboardCode(VK_CONTROL), KeyboardCode(VK_MENU), KeyboardCode(VK_LWIN), KeyboardCode(VK_RWIN), KeyboardCode(VK_APPS), KeyboardCode(VK_LSHIFT), KeyboardCode(VK_RSHIFT), KeyboardCode(VK_LCONTROL), KeyboardCode(VK_RCONTROL), KeyboardCode(VK_LMENU), // For Windows the F12 key is reserved for use by the debugger at all // times, so it should not be registered as a hot key. See: // https://msdn.microsoft.com/en-us//library/windows/desktop/ms646309(v=vs.85).aspx KeyboardCode(VK_F12) #endif }; HotkeyManager::HotkeyManager() { // Create the hotkeys m_HotKeys.push_back(new HotKeyCommandEnable(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandCenterPointer(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandWorkspace(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandIncreaseX(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandIncreaseY(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandDecreaseX(m_HotKeys.size())); m_HotKeys.push_back(new HotKeyCommandDecreaseY(m_HotKeys.size())); InitDefaults(); // Bind hotkey handler #if defined(__WXMSW__) wxWindow* mainWin = wxGetApp().GetController().GetMainWindow(); mainWin->Bind(wxEVT_HOTKEY, [this](wxKeyEvent& e) { this->HotkeyEventHandler(e); }); #endif } HotkeyManager::~HotkeyManager() { // free memory for (size_t i= 0; i< m_HotKeys.size(); i++) { delete m_HotKeys[i]; } #if defined(__WXMSW__) // TODO: unbind handler. See: // http://docs.wxwidgets.org/trunk/classwx_evt_handler.html#a2b7df8272075a96daea78cdd799c00da #endif } void HotkeyManager::ResetHotKeys() { // Disable hot keys for (size_t i= 0; i< m_HotKeys.size(); i++) { DisableHotKey(*m_HotKeys[i]); } } bool HotkeyManager::SetHotKeyKeyboardCode (HotKey& hk, KeyboardCode kc) { if (hk.GetKey()== kc) return true; // Do nothing if is the same //if (FindByKeyboardCode(kc) != -1) return false; // Already in use // Is banned? for (size_t i= 0; i< sizeof(g_banned_hotkeys)/sizeof(KeyboardCode); ++i) { if (g_banned_hotkeys[i] == kc) return false; } bool wasEnabled= hk.IsEnabled(); if (wasEnabled) DisableHotKey(hk); hk.SetKey(kc); bool result= true; if (wasEnabled) result= EnableHotKey(hk); return result; } int HotkeyManager::FindByKeyboardCode (KeyboardCode kc) const { for (size_t i=0; i< m_HotKeys.size(); i++) { if (m_HotKeys[i]->GetKey() == kc) return i; } return -1; // not found } bool HotkeyManager::EnableHotKey(HotKey& hk) { bool result= true; if (!hk.IsEnabled()) { #if defined(__WXMSW__) wxWindow* mainWin = wxGetApp().GetController().GetMainWindow(); result = mainWin->RegisterHotKey(hk.id_, 0, hk.GetKey().get_native()); #endif if (result) hk.SetEnabled(true); } return result; } void HotkeyManager::DisableHotKey(HotKey& hk) { if (hk.IsEnabled()) { #if defined(__WXMSW__) wxWindow* mainWin = wxGetApp().GetController().GetMainWindow(); mainWin->UnregisterHotKey(hk.id_); #endif hk.SetEnabled(false); } } void HotkeyManager::HotkeyEventHandler(wxKeyEvent& event) { KeyboardCode kc(event.GetRawKeyCode()); SLOG_DEBUG("HotKey Handler called, KeyboardCode: %d (%s)", kc.get_native(), static_cast(kc.GetName().mb_str())); int i= FindByKeyboardCode(kc); if (i== -1) return; if (m_HotKeys[i]->IsEnabled()) m_HotKeys[i]->Command(); } // TODO: to avoid synchronization problems, implement this by deriving // from wxEvtHandler and sending hot-key messages using wxPostEvent. This // way we make sure that all hot-key driven actions are always executed from // the main thread. This approach will also make easier the transition to // an implementation based on keyboard hooks void HotkeyManager::CheckKeyboardStatus() { #if defined(__WXGTK__) BEGIN_GUI_CALL_MUTEX() KeyboardCode kc = KeyboardCode::ReadKeyCode(); if (kc!= m_lastKeyCode) { m_lastKeyCode= kc; int index= FindByKeyboardCode(kc); if (index != -1 and m_HotKeys[index]->IsEnabled()) m_HotKeys[index]->Command(); } END_GUI_CALL_MUTEX() #endif // __WXGTK___ } void HotkeyManager::InitDefaults() { // Hotkeys disabled by default for (size_t i= 0; i< m_HotKeys.size(); i++) { DisableHotKey(*m_HotKeys[i]); } } void HotkeyManager::WriteProfileData(wxConfigBase* pConfObj) { pConfObj->SetPath (_T("hotKeyManager")); for (unsigned int i=0; iWrite(hk->GetName(), hk->IsEnabled()); pConfObj->Write(hk->GetName() + _T("Key"), static_cast(hk->GetKey().get_native())); } pConfObj->SetPath (_T("..")); } void HotkeyManager::ReadProfileData(wxConfigBase* pConfObj) { pConfObj->SetPath (_T("hotKeyManager")); for (unsigned int i=0; iIsEnabled(); pConfObj->Read(hk->GetName(), &isEnabled); int rawKeyCode= hk->GetKey().get_native(); pConfObj->Read(m_HotKeys[i]->GetName() + _T("Key"), &rawKeyCode); DisableHotKey(*hk); SetHotKeyKeyboardCode (*hk, KeyboardCode(rawKeyCode)); if (isEnabled) EnableHotKey(*hk); } pConfObj->SetPath (_T("..")); } } // namespace