← Back to team overview

kicad-developers team mailing list archive

Re: Need testers for a patch to merge hotkeys and accelerators

 

Le 03/10/2017 à 21:01, jp charras a écrit :
> Hi All,
> 
> Currently, when a key is used as hotkey and if we want to display it in a sub-menu of the main menu,
> because it becomes a accelerator key, we need to modify it (adding shift or alt modifier) when the
> action differs (uses the mouse position) when called from a menu or a key.
> 
> Although there are not a lot of cases (zoom in and out are 2 cases, and there are more cases in
> Eeschema), this is annoying for 2 reasons:
> - Many users do not know the difference between a accelerator key and a hotkey.
> - 2 similar actions use 2 keys instead of only one key, and we do not have a lot of available keys
> for hotkeys, so wasting a few keys is very annoying.
> 
> I wrote a patch to use the same key as accelerator key and hotkey.
> 
> In fact, if a menu uses (for a accelerator key) the same key as a hotkey, the key event is not sent
> to this menu, and the "accelerator key" becomes just a comment in menu.
> 
> To do that, the EVT_CHAR_HOOK key event is now managed by the main frame and is filtered, and not
> sent to the GUI if a hotkey handles this key event (this is the normal way to handle keys whenn we
> have special requirements).
> 
> Unfortunately, the way EVT_CHAR_HOOK and EVT_CHAR key events are exactly working is highly dependent
> of platforms, and a bit tricky.
> 
> I tested this patch on Windows 32 bits, and partially on Linux (I was not able to test the python
> console), but not on OSX.
> 
> Obviously, it must be tested (both in legacy canvas and GEL canvas) on OSX, and Linux (and of course
> on Windows 64 bits), and especially with Pcbnew in python console:
> are all chars captured in the console, especially the 2 accelerators 'O' and 'X'
> 
> Thanks.

I fixed some issues found in my first patch.
I also tested  the wxpython console both on Windows and Linux.
I fixed an issue on Linux, and the python console works now.

So tests on OSX are now needed.

Thanks

-- 
Jean-Pierre CHARRAS

 common/draw_frame.cpp           | 17 ++++++++++++++++-
 common/draw_panel.cpp           |  2 +-
 common/tool/tool_dispatcher.cpp | 31 +++++++++++--------------------
 common/tool/tool_manager.cpp    | 12 ++++++++----
 eeschema/controle.cpp           | 24 ++++++++++++------------
 eeschema/menubar.cpp            | 32 ++++++++++++++++----------------
 eeschema/schframe.h             |  1 -
 include/class_draw_panel_gal.h  |  9 +++++++++
 include/draw_frame.h            | 18 ++++++++++++++++--
 include/tool/tool_manager.h     |  6 ++++--
 pcbnew/controle.cpp             | 10 ++++------
 pcbnew/menubar_modedit.cpp      |  4 ++--
 pcbnew/menubar_pcbframe.cpp     |  6 +++---
 pcbnew/moduleframe.cpp          | 10 ++++------
 14 files changed, 106 insertions(+), 76 deletions(-)

diff --git a/common/draw_frame.cpp b/common/draw_frame.cpp
index d559a84..db3a312 100644
--- a/common/draw_frame.cpp
+++ b/common/draw_frame.cpp
@@ -95,6 +95,8 @@ const wxChar EDA_DRAW_FRAME::CANVAS_TYPE_KEY[] = wxT( "canvas_type" );
 static const wxString MaxUndoItemsEntry(wxT( "DevelMaxUndoItems" ) );
 
 BEGIN_EVENT_TABLE( EDA_DRAW_FRAME, KIWAY_PLAYER )
+    EVT_CHAR_HOOK( EDA_DRAW_FRAME::OnCharHook )
+
     EVT_MOUSEWHEEL( EDA_DRAW_FRAME::OnMouseEvent )
     EVT_MENU_OPEN( EDA_DRAW_FRAME::OnMenuOpen )
     EVT_ACTIVATE( EDA_DRAW_FRAME::OnActivate )
@@ -227,6 +229,14 @@ EDA_DRAW_FRAME::~EDA_DRAW_FRAME()
 }
 
 
+void EDA_DRAW_FRAME::OnCharHook( wxKeyEvent& event )
+{
+    // Key events can be filtered here.
+    // Currently no filtering is made.
+    event.Skip();
+}
+
+
 void EDA_DRAW_FRAME::ReleaseFile()
 {
     m_file_checker = nullptr;
@@ -1317,9 +1327,10 @@ void EDA_DRAW_FRAME::RefreshCrossHair( const wxPoint &aOldPos,
     }
 }
 
-void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
+bool EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
                                                 bool aSnapToGrid )
 {
+    bool key_handled = false;
 
     // If requested snap the current position to the grid
     if( aSnapToGrid )
@@ -1344,6 +1355,7 @@ void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
     case WXK_LEFT:
     case WXK_NUMPAD6:
     case WXK_RIGHT:
+        key_handled = true;
         {
             /* Here's a tricky part: when doing cursor key movement, the
              * 'previous' point should be taken from memory, *not* from the
@@ -1399,6 +1411,7 @@ void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
             default: /* Can't happen since we entered the statement */
                 break;
             }
+
             m_canvas->MoveCursor( *aPos );
             m_movingCursorWithKeyboard = true;
         }
@@ -1407,6 +1420,8 @@ void EDA_DRAW_FRAME::GeneralControlKeyMovement( int aHotKey, wxPoint *aPos,
     default:
         break;
     }
+
+    return key_handled;
 }
 
 
diff --git a/common/draw_panel.cpp b/common/draw_panel.cpp
index baf5e98..cd4ac70 100644
--- a/common/draw_panel.cpp
+++ b/common/draw_panel.cpp
@@ -1338,7 +1338,7 @@ void EDA_DRAW_PANEL::OnMouseEvent( wxMouseEvent& event )
 
 void EDA_DRAW_PANEL::OnCharHook( wxKeyEvent& event )
 {
-    event.Skip();
+    OnKeyEvent( event );//event.Skip();
 }
 
 void EDA_DRAW_PANEL::OnKeyEvent( wxKeyEvent& event )
diff --git a/common/tool/tool_dispatcher.cpp b/common/tool/tool_dispatcher.cpp
index 5c9113f..45388bf 100644
--- a/common/tool/tool_dispatcher.cpp
+++ b/common/tool/tool_dispatcher.cpp
@@ -254,7 +254,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
 // the GUI. These key codes are known to be used in pcbnew to move the cursor
 // or change active layer, and have a default action (moving scrollbar button) if
 // the event is skipped
-bool isKeySpecialCode( int aKeyCode )
+/*bool isKeySpecialCode( int aKeyCode )
 {
     const enum wxKeyCode special_keys[] =
     {
@@ -274,6 +274,7 @@ bool isKeySpecialCode( int aKeyCode )
 
     return isInList;
 }
+*/
 
 /* aHelper class that convert some special key codes to an equivalent.
  *  WXK_NUMPAD_UP to WXK_UP,
@@ -309,7 +310,8 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
     bool motion = false, buttonEvents = false;
     boost::optional<TOOL_EVENT> evt;
     int key = 0;    // key = 0 if the event is not a key event
-    bool keyIsSpecial = false;  // True if the key is a special key code
+    //bool keyIsSpecial = false;  // True if the key is a special key code
+    bool key_handled = false;
 
     int type = aEvent.GetEventType();
 
@@ -358,21 +360,9 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
     {
         wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
         key = ke->GetKeyCode();
-        keyIsSpecial = isKeySpecialCode( key );
+        //keyIsSpecial = isKeySpecialCode( key );
 
-        // if the key event must be skipped, skip it here if the event is a wxEVT_CHAR_HOOK
-        // and do nothing.
-        // a wxEVT_CHAR will be fired by wxWidgets later for this key.
-        if( type == wxEVT_CHAR_HOOK )
-        {
-            if( !keyIsSpecial )
-            {
-                aEvent.Skip();
-                return;
-            }
-            else
-            key = translateSpecialCode( key );
-        }
+        key = translateSpecialCode( key );
 
         int mods = decodeModifiers( ke );
 
@@ -396,7 +386,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
     }
 
     if( evt )
-        m_toolMgr->ProcessEvent( *evt );
+        key_handled = m_toolMgr->ProcessEvent( *evt );
 
     // pass the event to the GUI, it might still be interested in it
     // Note wxEVT_CHAR_HOOK event is already skipped for special keys not used by kicad
@@ -418,10 +408,11 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
     // The suitable Skip is already called, but the wxEVT_CHAR
     // must be Skipped (sent to GUI).
     // Otherwise accelerators and shortcuts in main menu or toolbars are not seen.
-#ifndef __APPLE__
-    if( type == wxEVT_CHAR && !keyIsSpecial )
+//#ifndef __APPLE__
+    if( (type == wxEVT_CHAR || type == wxEVT_CHAR_HOOK )
+        /*&& !keyIsSpecial*/ && !key_handled )
         aEvent.Skip();
-#endif
+//#endif
 
     updateUI();
 }
diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp
index d1c7f95..9c869ed 100644
--- a/common/tool/tool_manager.cpp
+++ b/common/tool/tool_manager.cpp
@@ -728,9 +728,9 @@ TOOL_MANAGER::ID_LIST::iterator TOOL_MANAGER::finishTool( TOOL_STATE* aState )
 }
 
 
-void TOOL_MANAGER::ProcessEvent( const TOOL_EVENT& aEvent )
+bool TOOL_MANAGER::ProcessEvent( const TOOL_EVENT& aEvent )
 {
-    processEvent( aEvent );
+    bool hotkey_handled = processEvent( aEvent );
 
     if( TOOL_STATE* active = GetCurrentToolState() )
     {
@@ -742,6 +742,8 @@ void TOOL_MANAGER::ProcessEvent( const TOOL_EVENT& aEvent )
         EDA_DRAW_FRAME* f = static_cast<EDA_DRAW_FRAME*>( GetEditFrame() );
         f->GetGalCanvas()->Refresh();    // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
     }
+
+    return hotkey_handled;
 }
 
 
@@ -859,11 +861,11 @@ void TOOL_MANAGER::popViewControls()
 }
 
 
-void TOOL_MANAGER::processEvent( const TOOL_EVENT& aEvent )
+bool TOOL_MANAGER::processEvent( const TOOL_EVENT& aEvent )
 {
     // Early dispatch of events destined for the TOOL_MANAGER
     if( !dispatchStandardEvents( aEvent ) )
-        return;
+        return true;
 
     dispatchInternal( aEvent );
     dispatchActivation( aEvent );
@@ -876,6 +878,8 @@ void TOOL_MANAGER::processEvent( const TOOL_EVENT& aEvent )
         m_eventQueue.pop_front();
         processEvent( event );
     }
+
+    return false;
 }
 
 bool TOOL_MANAGER::IsToolActive( TOOL_ID aId ) const
diff --git a/eeschema/controle.cpp b/eeschema/controle.cpp
index 82f2ca0..2876b96 100644
--- a/eeschema/controle.cpp
+++ b/eeschema/controle.cpp
@@ -216,8 +216,6 @@ SCH_ITEM* SCH_EDIT_FRAME::LocateItem( const wxPoint& aPosition, const KICAD_T aF
 
 bool SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
 {
-    bool eventHandled = true;
-
     // Filter out the 'fake' mouse motion after a keyboard movement
     if( !aHotKey && m_movingCursorWithKeyboard )
     {
@@ -239,7 +237,7 @@ bool SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KE
 
     wxPoint pos = aPosition;
     wxPoint oldpos = GetCrossHairPosition();
-    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
+    bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
 
     // Update cursor position.
     SetCrossHairPosition( pos, snapToGrid );
@@ -248,23 +246,25 @@ bool SCH_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KE
     if( aHotKey )
     {
         SCH_SCREEN* screen = GetScreen();
+        bool hk_handled;
 
         if( screen->GetCurItem() && screen->GetCurItem()->GetFlags() )
-            eventHandled = OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
+            hk_handled = OnHotKey( aDC, aHotKey, aPosition, screen->GetCurItem() );
         else
-            eventHandled = OnHotKey( aDC, aHotKey, aPosition, NULL );
+            hk_handled = OnHotKey( aDC, aHotKey, aPosition, NULL );
+
+        if( hk_handled )
+            keyHandled = true;
     }
 
     UpdateStatusBar();    /* Display cursor coordinates info */
 
-    return eventHandled;
+    return keyHandled;
 }
 
 
 bool LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
 {
-    bool eventHandled = true;
-
     // Filter out the 'fake' mouse motion after a keyboard movement
     if( !aHotKey && m_movingCursorWithKeyboard )
     {
@@ -286,20 +286,20 @@ bool LIB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KE
 
     wxPoint pos = aPosition;
     wxPoint oldpos = GetCrossHairPosition();
-    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
+    bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
 
     // Update the cursor position.
     SetCrossHairPosition( pos, snapToGrid );
     RefreshCrossHair( oldpos, aPosition, aDC );
 
-    if( aHotKey )
+    if( aHotKey && OnHotKey( aDC, aHotKey, aPosition, NULL ) )
     {
-        eventHandled = OnHotKey( aDC, aHotKey, aPosition, NULL );
+        keyHandled = true;
     }
 
     UpdateStatusBar();
 
-    return eventHandled;
+    return keyHandled;
 }
 
 
diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp
index 056a8ac..c7fb23e 100644
--- a/eeschema/menubar.cpp
+++ b/eeschema/menubar.cpp
@@ -153,11 +153,11 @@ void prepareViewMenu( wxMenu* aParentMenu )
      */
 
     text = AddHotkeyName( _( "Zoom &In" ), g_Schematic_Hokeys_Descr,
-                          HK_ZOOM_IN, IS_ACCELERATOR );  // add an accelerator, not a shortcut
+                          HK_ZOOM_IN/*, IS_ACCELERATOR*/ );  // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) );
 
     text = AddHotkeyName( _( "Zoom &Out" ), g_Schematic_Hokeys_Descr,
-                          HK_ZOOM_OUT, IS_ACCELERATOR );  // add accelerator, not a shortcut
+                          HK_ZOOM_OUT/*, IS_ACCELERATOR*/ );  // add accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) );
 
     text = AddHotkeyName( _( "&Fit on Screen" ), g_Schematic_Hokeys_Descr, HK_ZOOM_AUTO );
@@ -191,59 +191,59 @@ void preparePlaceMenu( wxMenu* aParentMenu )
     wxString text;
 
     text = AddHotkeyName( _( "&Component" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_NEW_COMPONENT, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_NEW_COMPONENT/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_SCH_PLACE_COMPONENT, text,
                  HELP_PLACE_COMPONENTS,
                  KiBitmap( add_component_xpm ) );
 
     text = AddHotkeyName( _( "&Power Port" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_NEW_POWER, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_NEW_POWER/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_PLACE_POWER_BUTT, text,
                  HELP_PLACE_POWERPORT,
                  KiBitmap( add_power_xpm ) );
 
     text = AddHotkeyName( _( "&Wire" ), g_Schematic_Hokeys_Descr,
-                          HK_BEGIN_WIRE, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_BEGIN_WIRE/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_WIRE_BUTT, text,
                  HELP_PLACE_WIRE,
                  KiBitmap( add_line_xpm ) );
 
     text = AddHotkeyName( _( "&Bus" ), g_Schematic_Hokeys_Descr,
-                          HK_BEGIN_BUS, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_BEGIN_BUS/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_BUS_BUTT, text,
                  HELP_PLACE_BUS,
                  KiBitmap( add_bus_xpm ) );
 
     text = AddHotkeyName( _( "Wire to Bus &Entry" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_WIRE_ENTRY, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_WIRE_ENTRY/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_WIRETOBUS_ENTRY_BUTT, text,
                  HELP_PLACE_WIRE2BUS_ENTRY,
                  KiBitmap( add_line2bus_xpm ) );
 
     text = AddHotkeyName( _( "Bus &to Bus Entry" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_BUS_ENTRY, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_BUS_ENTRY/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_BUSTOBUS_ENTRY_BUTT, text,
                  HELP_PLACE_BUS2BUS_ENTRY,
                  KiBitmap( add_bus2bus_xpm ) );
 
     text = AddHotkeyName( _( "&No Connect Flag" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_NOCONN_FLAG, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_NOCONN_FLAG/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_NOCONN_BUTT, text, HELP_PLACE_NC_FLAG, KiBitmap( noconn_xpm ) );
 
     text = AddHotkeyName( _( "&Junction" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_JUNCTION, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_JUNCTION/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_JUNCTION_BUTT, text,
                  HELP_PLACE_JUNCTION,
                  KiBitmap( add_junction_xpm ) );
 
     text = AddHotkeyName( _( "&Label" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_LABEL, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_LABEL/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_LABEL_BUTT, text,
                  HELP_PLACE_NETLABEL,
                  KiBitmap( add_line_label_xpm ) );
 
     text = AddHotkeyName( _( "Gl&obal Label" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_GLABEL, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_GLABEL/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_GLABEL_BUTT, text,
                  HELP_PLACE_GLOBALLABEL,
                  KiBitmap( add_glabel_xpm ) );
@@ -251,14 +251,14 @@ void preparePlaceMenu( wxMenu* aParentMenu )
     aParentMenu->AppendSeparator();
 
     text = AddHotkeyName( _( "&Hierarchical Label" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_HLABEL, IS_ACCELERATOR );          // add an accelerator, not a shortcut
+                          HK_ADD_HLABEL/*, IS_ACCELERATOR*/ );          // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_HIERLABEL_BUTT,
                  text, HELP_PLACE_HIER_LABEL,
                  KiBitmap( add_hierarchical_label_xpm ) );
 
 
     text = AddHotkeyName( _( "Hierarchical &Sheet" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_HIER_SHEET, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_HIER_SHEET/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_SHEET_SYMBOL_BUTT, text,
                  HELP_PLACE_SHEET,
                  KiBitmap( add_hierarchical_subsheet_xpm ) );
@@ -278,13 +278,13 @@ void preparePlaceMenu( wxMenu* aParentMenu )
     aParentMenu->AppendSeparator();
 
     text = AddHotkeyName( _( "Graphic Pol&yline" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_GRAPHIC_POLYLINE, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_GRAPHIC_POLYLINE/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_LINE_COMMENT_BUTT, text,
                  HELP_PLACE_GRAPHICLINES,
                  KiBitmap( add_dashed_line_xpm ) );
 
     text = AddHotkeyName( _( "&Graphic Text" ), g_Schematic_Hokeys_Descr,
-                          HK_ADD_GRAPHIC_TEXT, IS_ACCELERATOR );    // add an accelerator, not a shortcut
+                          HK_ADD_GRAPHIC_TEXT/*, IS_ACCELERATOR*/ );    // add an accelerator, not a shortcut
     AddMenuItem( aParentMenu, ID_TEXT_COMMENT_BUTT, text,
                  HELP_PLACE_GRAPHICTEXTS,
                  KiBitmap( text_xpm ) );
diff --git a/eeschema/schframe.h b/eeschema/schframe.h
index c990fc2..0a5b212 100644
--- a/eeschema/schframe.h
+++ b/eeschema/schframe.h
@@ -1089,7 +1089,6 @@ public:
     int GetLabelIncrement() const { return m_repeatLabelDelta; }
 
 private:
-
     /**
      * Function Load_Component
      * loads from a library and places a component.
diff --git a/include/class_draw_panel_gal.h b/include/class_draw_panel_gal.h
index 3e33b67..2710b32 100644
--- a/include/class_draw_panel_gal.h
+++ b/include/class_draw_panel_gal.h
@@ -223,6 +223,15 @@ public:
      */
     int GetCurrentCursor() const { return m_currentCursor; }
 
+    /**
+     * A accessor to send key events to the gal canvas.
+     * used to send a wxEVT_CHAR_HOOK from the editor frame
+     * to the gal canvas and filter it
+     */
+    void OnKeyEvent( wxKeyEvent& aEvent )
+    {
+        onEvent( aEvent );
+    }
 
 protected:
     void onPaint( wxPaintEvent& WXUNUSED( aEvent ) );
diff --git a/include/draw_frame.h b/include/draw_frame.h
index 6c17ffd..536814e 100644
--- a/include/draw_frame.h
+++ b/include/draw_frame.h
@@ -158,8 +158,13 @@ protected:
     /**
      * Function GeneralControlKeyMovement
      * Handle the common part of GeneralControl dedicated to global
-     * cursor keys (i.e. cursor movement by keyboard) */
-    void GeneralControlKeyMovement( int aHotKey, wxPoint *aPos, bool aSnapToGrid );
+     * cursor keys (i.e. cursor movement by keyboard)
+     * @param aHotKey is the hotkey code
+     * @param aPos is the position of the cursor (initial then new)
+     * @param aSnapToGrid = true to force the cursor position on grid
+     * @return true if the hotkey code is handled (captured).
+     */
+    bool GeneralControlKeyMovement( int aHotKey, wxPoint *aPos, bool aSnapToGrid );
 
     /**
      * Move and refresh the crosshair after movement and call the mouse capture function.
@@ -194,6 +199,14 @@ public:
 
     ~EDA_DRAW_FRAME();
 
+    /** this function capture the key event before it is sent to the GUI.
+     * the basic frame does not capture this event.
+     * editor frames should override this event function to capture and filter
+     * these keys when they are used as hotkeys, and skip it if the key is not
+     * used as hotkey (otherwise the key events will be not sent to menus)
+     */
+    virtual void OnCharHook( wxKeyEvent& event );
+
     /**
      * Function LockFile
      * marks a schematic file as being in use.  Use ReleaseFile() to undo this.
@@ -571,6 +584,7 @@ public:
      * @param aDC A device context.
      * @param aPosition The current cursor position in logical (drawing) units.
      * @param aHotKey A key event used for application specific control if not zero.
+     * @return true if the hotkey code is handled (captured).
      */
     virtual bool GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey = 0 )
     {
diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h
index 19b3316..2762fd8 100644
--- a/include/tool/tool_manager.h
+++ b/include/tool/tool_manager.h
@@ -227,8 +227,9 @@ public:
     /**
      * Propagates an event to tools that requested events of matching type(s).
      * @param aEvent is the event to be processed.
+     * @return true if the event is a managed hotkey
      */
-    void ProcessEvent( const TOOL_EVENT& aEvent );
+    bool ProcessEvent( const TOOL_EVENT& aEvent );
 
     /**
      * Puts an event to the event queue to be processed at the end of event processing cycle.
@@ -491,7 +492,8 @@ private:
     void popViewControls();
 
     ///> Main function for event processing.
-    void processEvent( const TOOL_EVENT& aEvent );
+    ///> @return true if a hotkey was handled
+    bool processEvent( const TOOL_EVENT& aEvent );
 
     /// Index of registered tools current states, associated by tools' objects.
     TOOL_STATE_MAP m_toolState;
diff --git a/pcbnew/controle.cpp b/pcbnew/controle.cpp
index 70cb8ca..b27e76c 100644
--- a/pcbnew/controle.cpp
+++ b/pcbnew/controle.cpp
@@ -276,8 +276,6 @@ BOARD_ITEM* PCB_BASE_FRAME::PcbGeneralLocateAndDisplay( int aHotKeyCode )
 
 bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
 {
-    bool eventHandled = true;
-
     // Filter out the 'fake' mouse motion after a keyboard movement
     if( !aHotKey && m_movingCursorWithKeyboard )
     {
@@ -295,7 +293,7 @@ bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KE
 
     wxPoint oldpos = GetCrossHairPosition();
     wxPoint pos = aPosition;
-    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
+    bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
 
     // Put cursor in new position, according to the zoom keys (if any).
     SetCrossHairPosition( pos, snapToGrid );
@@ -336,12 +334,12 @@ bool PCB_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KE
 
     RefreshCrossHair( oldpos, aPosition, aDC );
 
-    if( aHotKey )
+    if( aHotKey && OnHotKey( aDC, aHotKey, aPosition ) )
     {
-        eventHandled = OnHotKey( aDC, aHotKey, aPosition );
+        keyHandled = true;
     }
 
     UpdateStatusBar();    // Display new cursor coordinates
 
-    return eventHandled;
+    return keyHandled;
 }
diff --git a/pcbnew/menubar_modedit.cpp b/pcbnew/menubar_modedit.cpp
index 9b6be27..bbeee3e 100644
--- a/pcbnew/menubar_modedit.cpp
+++ b/pcbnew/menubar_modedit.cpp
@@ -228,11 +228,11 @@ void FOOTPRINT_EDIT_FRAME::ReCreateMenuBar()
      * for Zoom in and Zoom out sub menus
      */
     text = AddHotkeyName( _( "Zoom &In" ), m_hotkeysDescrList,
-                          HK_ZOOM_IN, IS_ACCELERATOR );
+                          HK_ZOOM_IN/*, IS_ACCELERATOR*/ );
     AddMenuItem( viewMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) );
 
     text = AddHotkeyName( _( "Zoom &Out" ), m_hotkeysDescrList,
-                          HK_ZOOM_OUT, IS_ACCELERATOR );
+                          HK_ZOOM_OUT/*, IS_ACCELERATOR*/ );
     AddMenuItem( viewMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) );
 
     text = AddHotkeyName( _( "&Fit on Screen" ), m_hotkeysDescrList,
diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp
index 1b58790..a0ebde6 100644
--- a/pcbnew/menubar_pcbframe.cpp
+++ b/pcbnew/menubar_pcbframe.cpp
@@ -313,7 +313,7 @@ void preparePlaceMenu( wxMenu* aParentMenu )
                  _( "Add footprints" ), KiBitmap( module_xpm ) );
 
     text = AddHotkeyName( _( "&Track" ), g_Pcbnew_Editor_Hokeys_Descr,
-                          HK_ADD_NEW_TRACK, IS_ACCELERATOR );
+                          HK_ADD_NEW_TRACK/*, IS_ACCELERATOR*/ );
     AddMenuItem( aParentMenu, ID_TRACK_BUTT, text,
                  _( "Add tracks and vias" ), KiBitmap( add_tracks_xpm ) );
 
@@ -530,11 +530,11 @@ void prepareViewMenu( wxMenu* aParentMenu )
      * for Zoom in and Zoom out sub menus
      */
     text = AddHotkeyName( _( "Zoom &In" ), g_Pcbnew_Editor_Hokeys_Descr,
-                          HK_ZOOM_IN, IS_ACCELERATOR );
+                          HK_ZOOM_IN/*, IS_ACCELERATOR*/ );
     AddMenuItem( aParentMenu, ID_ZOOM_IN, text, HELP_ZOOM_IN, KiBitmap( zoom_in_xpm ) );
 
     text = AddHotkeyName( _( "Zoom &Out" ), g_Pcbnew_Editor_Hokeys_Descr,
-                          HK_ZOOM_OUT, IS_ACCELERATOR );
+                          HK_ZOOM_OUT/*, IS_ACCELERATOR*/ );
     AddMenuItem( aParentMenu, ID_ZOOM_OUT, text, HELP_ZOOM_OUT, KiBitmap( zoom_out_xpm ) );
 
     text = AddHotkeyName( _( "&Fit on Screen" ), g_Pcbnew_Editor_Hokeys_Descr,
diff --git a/pcbnew/moduleframe.cpp b/pcbnew/moduleframe.cpp
index 9b8cb1d..f7a3c85 100644
--- a/pcbnew/moduleframe.cpp
+++ b/pcbnew/moduleframe.cpp
@@ -736,8 +736,6 @@ void FOOTPRINT_EDIT_FRAME::Show3D_Frame( wxCommandEvent& event )
 
 bool FOOTPRINT_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition, EDA_KEY aHotKey )
 {
-    bool eventHandled = true;
-
     // Filter out the 'fake' mouse motion after a keyboard movement
     if( !aHotKey && m_movingCursorWithKeyboard )
     {
@@ -755,19 +753,19 @@ bool FOOTPRINT_EDIT_FRAME::GeneralControl( wxDC* aDC, const wxPoint& aPosition,
 
     wxPoint oldpos = GetCrossHairPosition();
     wxPoint pos = aPosition;
-    GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
+    bool keyHandled = GeneralControlKeyMovement( aHotKey, &pos, snapToGrid );
 
     SetCrossHairPosition( pos, snapToGrid );
     RefreshCrossHair( oldpos, aPosition, aDC );
 
-    if( aHotKey )
+    if( aHotKey && OnHotKey( aDC, aHotKey, aPosition ) )
     {
-        eventHandled = OnHotKey( aDC, aHotKey, aPosition );
+        keyHandled = true;
     }
 
     UpdateStatusBar();
 
-    return eventHandled;
+    return keyHandled;
 }
 
 

Follow ups

References