diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 58a82c3b5a..f40ba6818f 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -337,6 +337,7 @@ set( COMMON_SRCS status_popup.cpp systemdirsappend.cpp template_fieldnames.cpp + textentry_tricks.cpp trace_helpers.cpp undo_redo_container.cpp utf8.cpp diff --git a/common/scintilla_tricks.cpp b/common/scintilla_tricks.cpp index 7c776fd01f..a34e064c26 100644 --- a/common/scintilla_tricks.cpp +++ b/common/scintilla_tricks.cpp @@ -58,14 +58,14 @@ SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString } -bool IsCtrl( int aChar, const wxKeyEvent& e ) +bool SCINTILLA_TRICKS::isCtrl( int aChar, const wxKeyEvent& e ) { return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && !e.ShiftDown() && !e.MetaDown(); } -bool IsShiftCtrl( int aChar, const wxKeyEvent& e ) +bool SCINTILLA_TRICKS::isShiftCtrl( int aChar, const wxKeyEvent& e ) { return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && e.ShiftDown() && !e.MetaDown(); @@ -96,26 +96,35 @@ void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent ) m_te->Tab(); } } - else if( m_te->IsShown() && IsCtrl( 'Z', aEvent ) ) + else if( isCtrl( 'Z', aEvent ) ) { m_te->Undo(); } - else if( m_te->IsShown() && ( IsShiftCtrl( 'Z', aEvent ) || IsCtrl( 'Y', aEvent ) ) ) + else if( isShiftCtrl( 'Z', aEvent ) || isCtrl( 'Y', aEvent ) ) { m_te->Redo(); } - else if( IsCtrl( 'X', aEvent ) ) + else if( isCtrl( 'X', aEvent ) ) { m_te->Cut(); } - else if( IsCtrl( 'C', aEvent ) ) + else if( isCtrl( 'C', aEvent ) ) { m_te->Copy(); } - else if( IsCtrl( 'V', aEvent ) ) + else if( isCtrl( 'V', aEvent ) ) { m_te->Paste(); } + else if( aEvent.GetKeyCode() == WXK_BACK ) + { + m_te->DeleteBack(); + } + else if( aEvent.GetKeyCode() == WXK_DELETE ) + { + if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() ) + m_te->DeleteBack(); + } else { aEvent.Skip(); diff --git a/common/textentry_tricks.cpp b/common/textentry_tricks.cpp new file mode 100644 index 0000000000..a2286707b0 --- /dev/null +++ b/common/textentry_tricks.cpp @@ -0,0 +1,90 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors. + * + * 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 2 + * 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, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include +#include + +bool TEXTENTRY_TRICKS::isCtrl( int aChar, const wxKeyEvent& e ) +{ + return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && + !e.ShiftDown() && !e.MetaDown(); +} + + +bool TEXTENTRY_TRICKS::isShiftCtrl( int aChar, const wxKeyEvent& e ) +{ + return e.GetKeyCode() == aChar && e.ControlDown() && !e.AltDown() && + e.ShiftDown() && !e.MetaDown(); +} + + +void TEXTENTRY_TRICKS::OnCharHook( wxTextEntry* aTextEntry, wxKeyEvent& aEvent ) +{ + if( isCtrl( 'X', aEvent ) ) + { + aTextEntry->Cut(); + } + else if( isCtrl( 'C', aEvent ) ) + { + aTextEntry->Copy(); + } + else if( isCtrl( 'V', aEvent ) ) + { + aTextEntry->Paste(); + } + else if( aEvent.GetKeyCode() == WXK_BACK ) + { + long start, end; + aTextEntry->GetSelection( &start, &end ); + + if( start > end ) + { + aTextEntry->Remove( start, end ); + aTextEntry->SetInsertionPoint( start ); + } + else if (start == end && start > 0 ) + { + aTextEntry->Remove( start-1, start ); + aTextEntry->SetInsertionPoint( start-1 ); + } + } + else if( aEvent.GetKeyCode() == WXK_DELETE ) + { + long start, end; + aTextEntry->GetSelection( &start, &end ); + + if( start > end ) + { + aTextEntry->Remove( start, end ); + aTextEntry->SetInsertionPoint( start ); + } + } + else + { + aEvent.Skip(); + } +} + + diff --git a/common/tool/action_menu.cpp b/common/tool/action_menu.cpp index 79a48a0f0d..39cd54d3f2 100644 --- a/common/tool/action_menu.cpp +++ b/common/tool/action_menu.cpp @@ -35,7 +35,8 @@ #include #include #include - +#include +#include using namespace std::placeholders; @@ -357,6 +358,7 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent ) OPT_TOOL_EVENT evt; wxString menuText; wxEventType type = aEvent.GetEventType(); + wxWindow* focus = wxWindow::FindFocus(); if( type == wxEVT_MENU_OPEN ) { @@ -380,6 +382,40 @@ void ACTION_MENU::OnMenuEvent( wxMenuEvent& aEvent ) } else if( type == wxEVT_COMMAND_MENU_SELECTED ) { + // Despite our attempts to catch the theft of text editor CHAR_HOOK and CHAR events + // in TOOL_DISPATCHER::DispatchWxEvent, wxWidgets sometimes converts those it knows + // about into menu commands without ever generating the appropriate CHAR_HOOK and CHAR + // events first. + if( dynamic_cast( focus ) || dynamic_cast( focus ) ) + { + // Original key event has been lost, so we have to re-create it from the menu's + // wxAcceleratorEntry. + wxMenuItem* menuItem = FindItem( aEvent.GetId() ); + wxAcceleratorEntry* acceleratorKey = menuItem ? menuItem->GetAccel() : nullptr; + + if( acceleratorKey ) + { + wxKeyEvent keyEvent( wxEVT_CHAR_HOOK ); + keyEvent.m_keyCode = acceleratorKey->GetKeyCode(); + keyEvent.m_controlDown = ( acceleratorKey->GetFlags() & wxMOD_CONTROL ) > 0; + keyEvent.m_shiftDown = ( acceleratorKey->GetFlags() & wxMOD_SHIFT ) > 0; + keyEvent.m_altDown = ( acceleratorKey->GetFlags() & wxMOD_ALT ) > 0; + + if( dynamic_cast( focus ) ) + focus->HandleWindowEvent( keyEvent ); + else if( dynamic_cast( focus ) ) + TEXTENTRY_TRICKS::OnCharHook( dynamic_cast( focus ), keyEvent ); + + if( keyEvent.GetSkipped() ) + { + keyEvent.SetEventType( wxEVT_CHAR ); + focus->HandleWindowEvent( keyEvent ); + } + } + + return; + } + // Store the selected position, so it can be checked by the tools m_selected = aEvent.GetId(); diff --git a/common/tool/common_control.cpp b/common/tool/common_control.cpp index d8ed78131e..69143dc07b 100644 --- a/common/tool/common_control.cpp +++ b/common/tool/common_control.cpp @@ -92,7 +92,7 @@ int COMMON_CONTROL::ConfigurePaths( const TOOL_EVENT& aEvent ) // Do nothing here. // A error message is displayed after trying to load _pcbnew.kiface. } - } +} else { DIALOG_CONFIGURE_PATHS dlg( m_frame, nullptr ); diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp index 910f92e967..93056de393 100644 --- a/common/tool/tool_dispatcher.cpp +++ b/common/tool/tool_dispatcher.cpp @@ -37,7 +37,7 @@ #include #include - +#include ///> Stores information about a mouse button state struct TOOL_DISPATCHER::BUTTON_STATE @@ -413,6 +413,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) OPT evt; bool keyIsEscape = false; // True if the keypress was the escape key bool keyIsSpecial = false; // True if the key is a special key code + wxWindow* focus = wxWindow::FindFocus(); int type = aEvent.GetEventType(); @@ -420,7 +421,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) // is opened and is iconized on Windows). // In this case, give the focus to the parent frame (GAL canvas itself does not accept the // focus when iconized for some obscure reason) - if( wxWindow::FindFocus() == nullptr ) + if( focus == nullptr ) { wxWindow* window = dynamic_cast( m_toolMgr->GetToolHolder() ); @@ -484,9 +485,14 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent ) keyIsEscape = ( ke->GetKeyCode() == WXK_ESCAPE ); - // Never process key events for tools when a text entry has focus - if( !dynamic_cast( wxWindow::FindFocus() ) ) - evt = GetToolEvent( ke, &keyIsSpecial ); + if( dynamic_cast( focus ) || dynamic_cast( focus ) ) + { + // Never process key events for tools when a text entry has focus + aEvent.Skip(); + return; + } + + evt = GetToolEvent( ke, &keyIsSpecial ); } else if( type == wxEVT_MENU_OPEN || type == wxEVT_MENU_CLOSE || type == wxEVT_MENU_HIGHLIGHT ) { diff --git a/include/scintilla_tricks.h b/include/scintilla_tricks.h index d603738c9a..5b9d952ed9 100644 --- a/include/scintilla_tricks.h +++ b/include/scintilla_tricks.h @@ -41,6 +41,9 @@ public: void DoAutocomplete( const wxString& aPartial, wxArrayString aTokens ); protected: + bool isCtrl( int aChar, const wxKeyEvent& e ); + bool isShiftCtrl( int aChar, const wxKeyEvent& e ); + void onCharHook( wxKeyEvent& aEvent ); void onScintillaUpdateUI( wxStyledTextEvent& aEvent ); diff --git a/include/textentry_tricks.h b/include/textentry_tricks.h new file mode 100644 index 0000000000..fc7261d336 --- /dev/null +++ b/include/textentry_tricks.h @@ -0,0 +1,44 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 KiCad Developers, see change_log.txt for contributors. + * + * 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 2 + * 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, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef TEXTENTRY_TRICKS_H +#define TEXTENTRY_TRICKS_H + + +#include + +/** + * TEXTENTRY_TRICKS + * is used to add cut/copy/paste to a wxTextEntry instance. While these are normally handled + * witout our intervention, this is not always the case. + */ +struct TEXTENTRY_TRICKS +{ + static void OnCharHook( wxTextEntry* aTextEntry, wxKeyEvent& aEvent ); + +protected: + static bool isCtrl( int aChar, const wxKeyEvent& e ); + static bool isShiftCtrl( int aChar, const wxKeyEvent& e ); +}; + +#endif // TEXTENTRY_TRICKS_H diff --git a/include/tool/action_menu.h b/include/tool/action_menu.h index 832be8746f..dc7634e4ca 100644 --- a/include/tool/action_menu.h +++ b/include/tool/action_menu.h @@ -31,6 +31,7 @@ #include #include +#include #include class TOOL_INTERACTIVE;