Author Topic: hook "tab" key  (Read 33520 times)

Offline blueshake

  • Regular
  • ***
  • Posts: 459
hook "tab" key
« on: March 08, 2010, 08:47:42 am »
dear all:


mybe you have the function of eclipse,in eclipse editor,when you type "tab",and if the next char is one of ")]}",it will skip it. see the screen shot.so if we want to implement this function,we need to hook getkey donw message,in codelite, it just simple handle it in this way.see the quote.

and in codeblock ,I can not figure out how to do this.can somebode tell me how to do this in codeblock,thanks.
Quote
BEGIN_EVENT_TABLE(LEditor, wxScintilla)

    EVT_SCI_CHARADDED              (wxID_ANY, LEditor::OnCharAdded)
    EVT_SCI_MARGINCLICK            (wxID_ANY, LEditor::OnMarginClick)
    EVT_SCI_CALLTIP_CLICK          (wxID_ANY, LEditor::OnCallTipClick)
    EVT_SCI_DWELLEND               (wxID_ANY, LEditor::OnDwellEnd)
    EVT_SCI_UPDATEUI               (wxID_ANY, LEditor::OnSciUpdateUI)
    EVT_SCI_SAVEPOINTREACHED       (wxID_ANY, LEditor::OnSavePoint)
    EVT_SCI_SAVEPOINTLEFT          (wxID_ANY, LEditor::OnSavePoint)
    EVT_SCI_MODIFIED               (wxID_ANY, LEditor::OnChange)
    EVT_CONTEXT_MENU               (LEditor::OnContextMenu)
    EVT_KEY_DOWN                   (LEditor::OnKeyDown)
    EVT_LEFT_DOWN                  (LEditor::OnLeftDown)
    EVT_MIDDLE_DOWN                (LEditor::OnMiddleDown)
    EVT_MIDDLE_UP                  (LEditor::OnMiddleUp)
    EVT_LEFT_UP                    (LEditor::OnLeftUp)
    EVT_LEAVE_WINDOW               (LEditor::OnLeaveWindow)
    EVT_KILL_FOCUS                 (LEditor::OnFocusLost)
    EVT_SCI_DOUBLECLICK            (wxID_ANY, LEditor::OnLeftDClick)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_FIND_NEXT, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_REPLACE, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_REPLACEALL, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_BOOKMARKALL, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_CLOSE, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_FRD_CLEARBOOKMARKS, LEditor::OnFindDialog)
    EVT_COMMAND                    (wxID_ANY, wxEVT_CMD_JOB_STATUS_VOID_PTR, LEditor::OnHighlightThread)
    EVT_COMMAND                    (wxID_ANY, wxCMD_EVENT_REMOVE_MATCH_INDICATOR, LEditor::OnRemoveMatchInidicator)
END_EVENT_TABLE()

[attachment deleted by admin]
Keep low and hear the sadness of little dog.
I fall in love with a girl,but I don't dare to tell her.What should I do?

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5910
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: hook "tab" key
« Reply #1 on: March 08, 2010, 09:17:47 am »
I have tried, but failed. :(

In the codelite editor, say LEditor class, it is just derived from wxScintilla class, so it can hook the EVT_KEY_DOWN message.

But in Codeblocks, cbEditor class use wxScintilla as its member, I don't know how to hook the Key_down event.

By the way, if we can handle the message SCI_TAB from scintilla (see: http://www.scintilla.org/ScintillaDoc.html#KeyboardCommands), we can do the same thing.

hope some one can help you.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: hook "tab" key
« Reply #2 on: March 08, 2010, 11:44:07 am »
and in codeblock ,I can not figure out how to do this.can somebode tell me how to do this in codeblock,thanks.
Look into:
Code
void cbEditor::OnScintillaEvent(wxScintillaEvent& event)

Notice that you should do any listening via an (the) editor hook. It can even be implemented as plugin btw!
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline blueshake

  • Regular
  • ***
  • Posts: 459
Re: hook "tab" key
« Reply #3 on: March 08, 2010, 01:41:40 pm »
@morten

thanks for your answer.I will check into it. :D
Keep low and hear the sadness of little dog.
I fall in love with a girl,but I don't dare to tell her.What should I do?

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5910
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: hook "tab" key
« Reply #4 on: March 09, 2010, 03:30:37 am »
I don't know we can do it in the OnScintillaEvent(), because we don't have a  wxEVT_SCI_TAB defined in wxscintilla.h

See the code snippet :

Code
cbStyledTextCtrl* cbEditor::CreateEditor()
{
    m_ID = wxNewId();

    // avoid gtk-critical because of sizes less than -1 (can happen with wxAuiNotebook/cbAuiNotebook)
    wxSize size = m_pControl ? wxDefaultSize : GetSize();
    size.x = std::max(size.x, -1);
    size.y = std::max(size.y, -1);

    cbStyledTextCtrl* control = new cbStyledTextCtrl(this, m_ID, wxDefaultPosition, size);
    control->UsePopUp(false);

    wxString enc_name = Manager::Get()->GetConfigManager(_T("editor"))->Read(_T("/default_encoding"), wxEmptyString);
    m_pData->m_encoding = wxFontMapper::GetEncodingFromName(enc_name);

    // dynamic events
    Connect( m_ID,  -1, wxEVT_SCI_MARGINCLICK,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnMarginClick );
    Connect( m_ID,  -1, wxEVT_SCI_UPDATEUI,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorUpdateUI );
    Connect( m_ID,  -1, wxEVT_SCI_CHANGE,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorChange );
    Connect( m_ID,  -1, wxEVT_SCI_CHARADDED,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorCharAdded );
    Connect( m_ID,  -1, wxEVT_SCI_DWELLSTART,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorDwellStart );
    Connect( m_ID,  -1, wxEVT_SCI_DWELLEND,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorDwellEnd );
    Connect( m_ID,  -1, wxEVT_SCI_USERLISTSELECTION,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnUserListSelection );
    Connect( m_ID,  -1, wxEVT_SCI_MODIFIED,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorModified );

    // Now bind all *other* scintilla events to a common function so that editor hooks
    // can be informed for them too.
    // If you implement one of these events using a different function, do the following:
    //  * comment it out here,
    //  * "connect" it in the above block
    //  * and make sure you call OnScintillaEvent() from your new handler function
    // This will make sure that all editor hooks will be called when needed.
    int scintilla_events[] =
    {
//        wxEVT_SCI_CHANGE,
        wxEVT_SCI_STYLENEEDED,
//        wxEVT_SCI_CHARADDED,
        wxEVT_SCI_SAVEPOINTREACHED,
        wxEVT_SCI_SAVEPOINTLEFT,
        wxEVT_SCI_ROMODIFYATTEMPT,
        wxEVT_SCI_KEY,
        wxEVT_SCI_DOUBLECLICK,
//        wxEVT_SCI_UPDATEUI,
//        wxEVT_SCI_MODIFIED,
        wxEVT_SCI_MACRORECORD,
//        wxEVT_SCI_MARGINCLICK,
        wxEVT_SCI_NEEDSHOWN,
        wxEVT_SCI_PAINTED,
//        wxEVT_SCI_USERLISTSELECTION,
        wxEVT_SCI_URIDROPPED,
//        wxEVT_SCI_DWELLSTART,
//        wxEVT_SCI_DWELLEND,
        wxEVT_SCI_START_DRAG,
        wxEVT_SCI_DRAG_OVER,
        wxEVT_SCI_DO_DROP,
        wxEVT_SCI_ZOOM,
        wxEVT_SCI_HOTSPOT_CLICK,
        wxEVT_SCI_HOTSPOT_DCLICK,
        wxEVT_SCI_CALLTIP_CLICK,
        wxEVT_SCI_AUTOCOMP_SELECTION,
//        wxEVT_SCI_INDICATOR_CLICK,
//        wxEVT_SCI_INDICATOR_RELEASE,

        -1 // to help enumeration of this array
    };
    int i = 0;
    while (scintilla_events[i] != -1)
    {
        Connect( m_ID,  -1, scintilla_events[i],
                      (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                      &cbEditor::OnScintillaEvent );
        ++i;
    }

    return control;
}


We can only handle all the events in the scintilla_events array, either commented events or uncommented events. But the "tab" event will never carried in the wxEVT_SCI_KEY, because from the docs:

http://www.scintilla.org/ScintillaDoc.html#SCN_KEY

Quote
SCN_KEY
Reports all keys pressed but not consumed by Scintilla.

Since I think the "tab" event is already consumed by Scintilla internally, the only chance we can hook the tab event is the "SCI_TAB" stated in the
http://www.scintilla.org/ScintillaDoc.html#KeyboardCommands

which is not implemented in wxScintilla.

I'm not sure all my comments is right. :D
« Last Edit: March 09, 2010, 03:32:24 am by ollydbg »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #5 on: March 24, 2010, 02:12:05 pm »
I solved this problem.

Code
cbStyledTextCtrl* cbEditor::CreateEditor()
{
    m_ID = wxNewId();

    // avoid gtk-critical because of sizes less than -1 (can happen with wxAuiNotebook/cbAuiNotebook)
    wxSize size = m_pControl ? wxDefaultSize : GetSize();
    size.x = std::max(size.x, -1);
    size.y = std::max(size.y, -1);

    cbStyledTextCtrl* control = new cbStyledTextCtrl(this, m_ID, wxDefaultPosition, size);
    control->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(cbEditor::OnKeyDown));

Notice:
    control->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(cbEditor::OnKeyDown));

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #6 on: March 25, 2010, 05:18:13 pm »
I make a patch for this, welcome to test.


[attachment deleted by admin]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5910
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: hook "tab" key
« Reply #7 on: March 26, 2010, 01:59:31 am »
I make a patch for this, welcome to test.


I found a bug:

When I enter this:
Code
void f(
Then, I will get the close parenthesis auto added.
Code
void f(|)
But at this moment, I press backspace key, then the opening parenthesis was deleted but the close parenthesis still there.
Code
void f)

Except this bug, all the other functions works really nice!!! Thanks for the contribution.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #8 on: March 26, 2010, 04:29:42 am »
I make a patch for this, welcome to test.


I found a bug:

When I enter this:
Code
void f(
Then, I will get the close parenthesis auto added.
Code
void f(|)
But at this moment, I press backspace key, then the opening parenthesis was deleted but the close parenthesis still there.
Code
void f)

Except this bug, all the other functions works really nice!!! Thanks for the contribution.
Fix now.


[attachment deleted by admin]

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: hook "tab" key
« Reply #9 on: March 26, 2010, 07:24:48 am »
Fix now.
Some remarks concerning this patch:
1.) Methods should not start like "No", "Dont", "Not". This is hard to read. Instead always call a method like e.g. "AllowTabSmartJump" and change the break statement to "if (!AllowTabSmartJump()) break;"
2.) The trial for AllowTabSmartJump() should be the first statement in the method, like:
Code
if (!AllowTabSmartJump())
{
    event.Skip();
    return;
}
3.) These statements look weird to me:
Code
        case _T('\''):
        case 57:    // (
        case 0x91:  // {
You are using character comparison, then integer and finally hex. Why? Couldn't this be consistent, readable like e.g. all of type char?
4.) It does not use our code style (indention of 4 spaces)

...if you keep that in mind then it easier for us to integrate with the C::B sources.

...sorry for nut-picking. Take it as a hint for future work.
« Last Edit: March 26, 2010, 07:26:53 am by MortenMacFly »
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #10 on: March 26, 2010, 08:21:30 am »
Hi, morten, thanks for your tips.
The following patch should solve your related issues.

Code
Index: src/include/cbstyledtextctrl.h
===================================================================
--- src/include/cbstyledtextctrl.h (revision 6196)
+++ src/include/cbstyledtextctrl.h (working copy)
@@ -24,9 +24,13 @@
         void OnKillFocus(wxFocusEvent& event);
         void OnGetFocus(wxFocusEvent& event);
         void OnGPM(wxMouseEvent& event);
+        void OnKeyDown(wxKeyEvent& event);
+        void OnKeyUp(wxKeyEvent& event);
+        bool AllowTabSmartJump();
 
         wxWindow* m_pParent;
         wxLongLong m_lastFocusTime;
+        bool m_tabSmartJump;
 
         DECLARE_EVENT_TABLE()
 };
Index: src/sdk/cbstyledtextctrl.cpp
===================================================================
--- src/sdk/cbstyledtextctrl.cpp (revision 6196)
+++ src/sdk/cbstyledtextctrl.cpp (working copy)
@@ -18,17 +18,23 @@
 #include "editorbase.h" // DisplayContextMenu
 #include "prep.h" // platform::gtk
 
+static const wxString s_leftBrace(_T("([{'\""));
+static const wxString s_rightBrace(_T(")]}'\""));
+
 BEGIN_EVENT_TABLE(cbStyledTextCtrl, wxScintilla)
     EVT_CONTEXT_MENU(cbStyledTextCtrl::OnContextMenu)
     EVT_KILL_FOCUS(cbStyledTextCtrl::OnKillFocus)
     EVT_MIDDLE_DOWN(cbStyledTextCtrl::OnGPM)
     EVT_SET_FOCUS(cbStyledTextCtrl::OnGetFocus)
+    EVT_KEY_DOWN(cbStyledTextCtrl::OnKeyDown)
+    EVT_KEY_UP(cbStyledTextCtrl::OnKeyUp)
 END_EVENT_TABLE()
 
 cbStyledTextCtrl::cbStyledTextCtrl(wxWindow* pParent, int id, const wxPoint& pos, const wxSize& size, long style)
     : wxScintilla(pParent, id, pos, size, style),
     m_pParent(pParent),
-    m_lastFocusTime(0L)
+    m_lastFocusTime(0L),
+    m_tabSmartJump(false)
 {
     //ctor
 }
@@ -103,3 +109,125 @@
         SetSelectionVoid(start, end);
     }
 } // end of OnGPM
+
+void cbStyledTextCtrl::OnKeyDown(wxKeyEvent& event)
+{
+    int keyCode = event.GetKeyCode();
+    switch (keyCode)
+    {
+        case WXK_TAB:
+        {
+            if (m_tabSmartJump)
+            {
+                if (s_rightBrace.Find(GetCharAt(GetCurrentPos())) == wxNOT_FOUND)
+                {
+                    m_tabSmartJump = false;
+                }
+                else
+                {
+                    CharRight();
+                    return;
+                }
+            }
+        }
+        break;
+
+        case WXK_BACK:
+        {
+            if (m_tabSmartJump)
+            {
+                const int pos = GetCurrentPos();
+                const int index = s_leftBrace.Find(GetCharAt(pos - 1));
+                if (index != wxNOT_FOUND && GetCharAt(pos) == s_rightBrace.GetChar(index))
+                {
+                    CharRight();
+                    DeleteBack();
+                }
+            }
+        }
+        break;
+
+        case WXK_ESCAPE:
+        {
+            if (m_tabSmartJump)
+            {
+                m_tabSmartJump = false;
+                CharLeft();
+                Tab();
+                return;
+            }
+        }
+        break;
+
+        case WXK_RETURN:
+        {
+            m_tabSmartJump = false;
+        }
+        break;
+    }
+
+    event.Skip();
+}
+
+void cbStyledTextCtrl::OnKeyUp(wxKeyEvent& event)
+{
+    const int keyCode = event.GetKeyCode();
+    switch (keyCode)
+    {
+        case _T('['):   // [ {
+        case _T('\''):  // ' "
+        case _T('9'):   // (
+        {
+            if (!AllowTabSmartJump()) break;
+
+            wxChar ch = keyCode;
+            if (event.ShiftDown())
+            {
+                if (keyCode == _T('\'')) ch = _T('"');
+                else if (keyCode == _T('9')) ch = _T('(');
+                else if (keyCode == _T('[')) ch = _T('{');
+            }
+
+            int index = s_leftBrace.Find(ch);
+            if (index != wxNOT_FOUND && GetCharAt(GetCurrentPos()) == s_rightBrace.GetChar(index))
+                m_tabSmartJump = true;
+            else if (keyCode == _T('\'')) // ' "
+                m_tabSmartJump = false;
+        }
+        break;
+
+        case _T(']'):   // ] }
+        case _T('0'):   // )
+        {
+            if (!AllowTabSmartJump()) break;
+            if (keyCode == _T('0') && !event.ShiftDown()) break;
+            m_tabSmartJump = false;
+        }
+        break;
+    }
+
+    event.Skip();
+}
+
+bool cbStyledTextCtrl::AllowTabSmartJump()
+{
+    int style = GetStyleAt(GetCurrentPos() - 2);
+    switch (GetLexer())
+    {
+        case wxSCI_LEX_CPP:
+        {
+            if (style != wxSCI_C_STRING && style != wxSCI_C_CHARACTER)
+                return true;
+            else
+                return !(style == wxSCI_C_STRING || style == wxSCI_C_CHARACTER);
+        }
+        case wxSCI_LEX_D:
+        {
+            if (style != wxSCI_D_STRING && style != wxSCI_D_CHARACTER)
+                return true;
+            else
+                return !(style == wxSCI_D_STRING || style == wxSCI_D_CHARACTER);
+        }
+    }
+    return false;
+}

[attachment deleted by admin]
« Last Edit: March 26, 2010, 09:02:48 am by Loaden »

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #11 on: March 26, 2010, 08:25:01 am »
But now I encountered difficulties: I do not know how to draw the lines for tips?
Moreover, whether it is necessary for drawing the root tips of the lines that do?
Everyone's opinion?

Offline Loaden

  • Lives here!
  • ****
  • Posts: 1014
Re: hook "tab" key
« Reply #12 on: March 26, 2010, 08:36:00 am »
2.) The trial for AllowTabSmartJump() should be the first statement in the method, like:
Code
if (!AllowTabSmartJump())
{
    event.Skip();
    return;
}
Here, I do not quite understand: Why did not directly break it, because at the end of the function, there implementation: 'event.Skip ();' ?

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: hook "tab" key
« Reply #13 on: March 26, 2010, 08:39:09 pm »
Here, I do not quite understand: Why did not directly break it, because at the end of the function, there implementation: 'event.Skip ();' ?
Yes, but there are computations in between which can be avoided. Namely event.GetKeyCode(); and the switch computation.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: hook "tab" key
« Reply #14 on: March 26, 2010, 08:43:22 pm »
Hehe... now after the modifications, isn't this:
Code
Index: src/include/cbstyledtextctrl.h
+    switch (GetLexer())
+    {
+        case wxSCI_LEX_CPP:
+        {
+            if (style != wxSCI_C_STRING && style != wxSCI_C_CHARACTER)
+                return true;
+            else
+                return !(style == wxSCI_C_STRING || style == wxSCI_C_CHARACTER);
+        }
+        case wxSCI_LEX_D:
+        {
+            if (style != wxSCI_D_STRING && style != wxSCI_D_CHARACTER)
+                return true;
+            else
+                return !(style == wxSCI_D_STRING || style == wxSCI_D_CHARACTER);
+        }
+    }
+    return false;
+}
The same like this:
Code
Index: src/include/cbstyledtextctrl.h
+    switch (GetLexer())
+    {
+        case wxSCI_LEX_CPP:
+        {
+            if (style != wxSCI_C_STRING && style != wxSCI_C_CHARACTER)
+                return true;
+        }
+        case wxSCI_LEX_D:
+        {
+            if (style != wxSCI_D_STRING && style != wxSCI_D_CHARACTER)
+                return true;
+        }
+    }
+    return false;
+}
???
:lol: :lol: :lol:
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ