Keyboard shortcut for next/previous incremental search result?



  • Hi,

    I find incremental search very useful and I almost always use it instead of the normal ‘Find’. However, I have a habit of doing an incremental search for certain text, then closing the incremental search bar, doing some writing, and then pressing F3/Shift-F3 (Next/Previous search result), expecting to go to the next/previous result based on what I entered in the incremental search bar; however, this actually just goes to the next/previous result from whatever the last regular ‘Find’ search I did was.

    Is there any way to use a shortcut that goes to the next/previous result of my incremental search, without having to re-open the window? Re-opening the bar, going to the next result, then closing it back again, adds two extra steps (opening + closing the bar) which it would be nice to eliminate…

    Thanks :)



  • @Andrew

    This has been an open issue since May 2016; see https://github.com/notepad-plus-plus/notepad-plus-plus/issues/1845

    Oddly enough, I remember that issue was there since I added a comment to it earlier today. :-D

    As a side note, why would you close the incremental-search window, only to have to reopen it? That sounds like two unnecessary steps to me. I always just leave it open; it is not that large that it takes up too much real estate…



  • Ah, thanks, didn’t come across that when I searched.

    The reason I close it is because it is just a single keystroke, Esc, whereas leaving it open would require me to use the mouse to switch focus back to the file itself – unless there is a keyboard shortcut for swapping focus? I like to do as much as possible with just the keyboard, swapping back and forth between mouse and keyboard is very cumbersome for me.



  • @Andrew

    Ah, that makes sense about the Esc key…

    If you’re willing to set up and use the Pythonscript plugin, I’ve created a solution that will allow assignments of keyboard shortcuts to do the next/previous-incremental-search-result functionality directly from the current editor window.

    Note that I didn’t do it for YOU…I thought about it after reading your post, and figured doing it would benefit ME! :-D

    Here’s how to accomplish the goal:

    • Create TWO new Pythonscripts, one named IncrSearchWindowPressFindNext.py and one named IncrSearchWindowPressFindPrev.py
    • Bind these Pythonscripts to TWO new keyboard shortcuts via the shortcut mapper (I use Shift+Ctrl+. for the “next” script and Shift+Ctrl+, for the “prev” script–these keystrokes are self-reminding as they are a variant of the < and > keys, the same as the text on the buttons in the Incremental Search window)

    The TWO scripts should have the SAME contents and those contents are:

    import ctypes
    from ctypes.wintypes import BOOL, HWND, LPARAM
    from inspect import currentframe, getframeinfo
    
    try:
        ISWPFNOP__incr_search_hwnd
    except NameError:
        ISWPFNOP__incr_search_hwnd = None
    
    def ISWPFNOP__main():  # (I)ncremental(S)earch(W)indow(P)ress(F)ind(N)ext(O)r(P)revious
    
        user32 = ctypes.windll.user32
        SendMessage = user32.SendMessageW
        FindWindow = user32.FindWindowW
        FindWindowEx = user32.FindWindowExW
        GetWindowText = user32.GetWindowTextW
        GetWindowTextLength = user32.GetWindowTextLengthW
        EnumChildWindows = user32.EnumChildWindows
        GetParent = user32.GetParent
        GetClassName = user32.GetClassNameW
        WNDENUMPROC = ctypes.WINFUNCTYPE(BOOL, HWND,LPARAM)
        create_ub256 = ctypes.create_unicode_buffer(256)
        BM_CLICK = 0x00F5
    
        if ISWPFNOP__incr_search_hwnd == None:
    
            # the goal with this section is to locate the Incremental Search window
    
            # this is technically overkill but it DOES define the Incremental Search window:
            incr_search_classname_and_text_seq_list = [
                u'#32770', u'',
                u'Button', u'X',
                u'Static', u'Find :',
                u'Edit',   None,          # 'None' here means the text of control is variable
                u'Button', u'<',
                u'Button', u'>',
                u'Button', u'&Highlight all',
                u'Button', u'Match &case',
                u'Static', None,          # 'None' here means the text of control is variable
                ]
    
            ISWPFNOP__main.seq_list_index = 0
    
            def child_window_enumeration_function(hwnd, _):
                class_name = create_ub256[:GetClassName(hwnd, create_ub256, 256)]
                if (ISWPFNOP__main.seq_list_index % 2) == 0 and \
                        class_name == incr_search_classname_and_text_seq_list[ISWPFNOP__main.seq_list_index]:
                    ISWPFNOP__main.seq_list_index += 1
                advance_seq_index = False
                if (ISWPFNOP__main.seq_list_index % 2) == 1:
                    text_length = GetWindowTextLength(hwnd)
                    if text_length == 0:
                        if incr_search_classname_and_text_seq_list[ISWPFNOP__main.seq_list_index] == u'' or \
                                incr_search_classname_and_text_seq_list[ISWPFNOP__main.seq_list_index] == None:
                            advance_seq_index = True
                    else:
                        buff = ctypes.create_unicode_buffer(text_length + 1)
                        GetWindowText(hwnd, buff, text_length + 1)
                        if incr_search_classname_and_text_seq_list[ISWPFNOP__main.seq_list_index] == buff.value or \
                                incr_search_classname_and_text_seq_list[ISWPFNOP__main.seq_list_index] == None:
                            advance_seq_index = True
                if advance_seq_index:
                    ISWPFNOP__main.seq_list_index += 1
                else:
                    ISWPFNOP__main.seq_list_index = 0
                continue_with_the_enumeration = True
                if ISWPFNOP__main.seq_list_index == len(incr_search_classname_and_text_seq_list):
                    # we surely found the Incremental-Search window! (it is the parent of the current child)
                    global ISWPFNOP__incr_search_hwnd; ISWPFNOP__incr_search_hwnd = GetParent(hwnd)
                    continue_with_the_enumeration = False
                return continue_with_the_enumeration
    
            EnumChildWindows(FindWindow(u'Notepad++', None), WNDENUMPROC(child_window_enumeration_function), 0)
    
        if ISWPFNOP__incr_search_hwnd != None:
    
            # save current view and doc index (and do it so that restoring later works well if a doc is cloned)
            saved_view = notepad.getCurrentView()
            saved_document_index = notepad.getCurrentDocIndex(saved_view)
    
            # find out which python file we are so we can determine which button to press:
            currently_running_pythonscript = getframeinfo(currentframe()).filename
            caption_of_button_to_press = '>' if 'FindNext' in currently_running_pythonscript else '<'
    
            # FINALLY, press the desired button:
            next_or_prev_button_hwnd = FindWindowEx(ISWPFNOP__incr_search_hwnd, 0, u'Button', caption_of_button_to_press)
            SendMessage(next_or_prev_button_hwnd, BM_CLICK, 0, 0)
    
            # return input focus to editor tab (focus was with incr search window):
            notepad.activateIndex(saved_view, saved_document_index)
    
    ISWPFNOP__main()
    

    If this (or ANY posting on the Notepad++ Community site) is useful, don’t reply with a “thanks”, simply up-vote ( click the ^ in the ^ 0 v area on the right ).



  • I was happy to find this thread because this is precisely what I need: shortcuts for find next (and previous) in incremental search. However, I failed implementing Scott’s suggestion.

    I created the two identical Phyton scripts with different names and saved them in the Notepad++ program folder under Notepad++/keyboard_shortcuts. (Or need I to place them at a different place?)

    Then I opened “Settings” --> “Shortcut mapper” in Notepad++, but I was not able to find any option to add, run or link the scripts I had created. What do I miss?



  • @Stefan-Boeters

    python scripts which need to interact with notepad++ do require python script plugin. Available for 32bit version only.

    Once installed you need to create a new script by using the python script plugin menu,
    copy the code into it, save it. Goto python script plugin configuration menu and put the newly created script to the menu items. Close. Now you can assign a shortcut,

    Cheers
    Claudia



  • @Stefan-Boeters said:

    what I need: shortcuts for find next (and previous) in incremental search

    If I interpret you literally then I think you mean you need keyboard shortcuts for these functions without leaving the incremental search window. The script above works only when the input focus is on a document tab window. Of course it could be changed to work when the input focus is in other places… But maybe that isn’t what you mean at all…hard to tell. :-)



  • OK, I see. I’ve now:

    (1) Installed the Python Script plugin,
    (2) Copied the Python scripts in the /plugins/PhytonScript/scripts folder
    (3) Added the scripts in Plugins --> Phyton Script --> Configuration to the menu items
    (4) Assigned shortcuts in Settings --> Shortcut Mapper --> Plugin Commands

    It works – but only partly. This is what happens:

    • When I open a file, open the incremental search window, search (ordinarily) for a text en then use the shortcuts for “FindNext” and “FindPrev”, nothing happens.
    • If I invoke the scripts via Plugins --> Python Scripts (rather than via shortcuts), one of them (“FindPrev”) does work, the other (“FindNext”) doesn’t.
    • If I use the shortcuts after the first call (via Plugins --> Python Scripts), “FindPrev” continues to work, but “FindNext” doesn’t.

    This has nothing to do with the specific shortcuts I use. I have changed both shortcuts for testing, and the result was the same.

    Is there anyone who has tried this as well? Is this an idiosyncrasy of my configuration or a general problem with Scott’s script?



  • @Scott-Sumner

    This is a subtlety I hadn’t paid attention to before. Now that I think about it, the following seems the “minimum keystrokes” solution to me:

    • You are in the document window in which you want to perform the search.
    • You type (Ctrl+Alt+I) for opening the Incremental Search window (which you need anyway to type the text you are searching for).
    • The first hit does not satisfy you, so you want the next one. This is while you are still in Incremental Search window, indeed.

    Do you happen to have time for modification of the script along this line? I have no experience with Python whatever, nor with coding this type of scripts anyway, so I’m afraid that modifying it myself is not an option.



  • @Stefan-Boeters said:

    Is there anyone who has tried this as well?

    I just tried the following series of steps:

    • grab N++ 7.5.1 portable install; unzip it
    • add Plugin Manager (ugh! and double-ugh!) by manual copying from my normal N++ install that I use normally
    • run virgin 7.5.1 (with Plugin Mgr addition)
    • install PS 1.0.8 via Plugin Mgr
    • change PS config to be AT STARTUP instead of LAZY
    • add the 2 scripts by copying text out of the code window from above in this thread, naming the files the same as indicated above
    • in PS Configuration, add the 2 scripts so that they can be found by Shortcut Mapper
    • in Shortcut Mapper, bind the “next” script to Ctrl+Shift+. (period)
    • in Shortcut Mapper, bind the “prev” script to Ctrl+Shift+, (comma)
    • invoke Incremental Search by pressing Ctrl+Alt+i
    • put some text in the Find: box and press Enter
    • press Esc (input focus is now back in doc I’m editing)
    • press Ctrl+Shift+, and verify selection changes to previous occurrence of my Find: text – IT DID!
    • press Ctrl+Shift+. and verify selection changes to next occurrence of my Find: text – IT DID!


  • @Stefan-Boeters said:

    The first hit does not satisfy you, so you want the next one. This is while you are still in Incremental Search window

    In this situation, just hit the Enter key. It will move the selection the the next match in the editor tab without leaving the Incremental Search pane.

    OR

    Press Esc (which closes the Incremental Search pane) and returns input focus to the document tab you were on when you invoked the Incremental Search, leaving you ready to press:

    • Ctrl+Shift+. (my shortcut, YSMV) to move the selection to the next match
    • Ctrl+Shift+, (my shortcut, YSMV) to move the selection to the previous match

    [YSMV = Your Shortcut May Vary]

    Note: You can’t run a PS from an assigned shortcut when the Incr Seach pane has input focus.



  • @Scott-Sumner

    Strangely enough, “FindPrev” works perfect in this way, whereas “FindNext” doesn’t.

    I’ve adjusted the following line in the script of “FindNext”:

    caption_of_button_to_press = '>' if 'FindNext' in currently_running_pythonscript else '<'
    

    to become

    caption_of_button_to_press = '>'
    

    (Actually you don’t need any experience with Python to do this). Now it works.

    This suggests that I had somehow misspelled the file name, but as far as I can see, I hadn’t. Anyway, with this (admittedly ugly) fix it does work for me. Thanks a lot. Even after this cumbersome start, the investment will pay off in the long run.



  • @Stefan-Boeters

    Yea…that was just my little technique to not have 2 files that differed only by one little thing–even having 2 identical files is not the best idea… It would be nice if you could pass arguments to pythonscripts or somehow know which keycombo invoked them, but this is not currently possible. [Actually both things are possible but not easy so I’ll just leave it there.] :-)



  • Hello @andrew, @stefan-boeters,@scott-sumner and All,

    I simply asked myself the question :

    How to have the editor window and the incremental search window present, at the same time and switch from one to the other, with a keyboard shortcut ? I found out a weird way to do it but, at least, it seems to work !


    I supposed that you previously got the incremental search windows, hitting the Alt + Ctrl + I shorctut, once :

    Now :

    • To move from the incremental search window to the main editor window, just hit the Win Logo key, twice :

      • a first hit on the Win logo key, to get the Start menu

      • a second hit, on the Win logo key, to close the Start menu

    As a result, the focus should be on the current editor window, with the cursor at its present location :-))

    • To move from the main editor window to the incremental search window, simply hit, again, the Alt + Ctrl + I shorctut

    And so on…

    This method works nice on my [ old ] Wind XP laptop ! Just verify that it’s the same, on newer Windows OS ?!

    Best Regards,

    guy038

    P.S. :

    ONCE the focus is on the incremental search window :

    • Press the Tab key, to cycle through the six zones ( Find zone, < and > buttons, Highlight all and Match case options , button X )

    • Press the Shift + Tab shortcut, to cycle, in reverse order

    • To set/unset the Highlight all or Match case options, you may, either :

      • From any location, hit the Alt + H or Alt + C shortcuts

      • From the exact location, just hit the Space key

    • When a direction is chosen ( < or > ), just press the Enter key, to go on searching, in the same direction

    • And, of course, hitting the Escape key, close the incremental search window !



  • @guy038 said:

    just hit the Win Logo key, twice

    Works for me on Windows 7 Enterprise SP1 64-bit, running Notepad++ 32-bit!

    The double hit of the Windows logo key also more efficiently (less keystrokes) solves the problem from this thread: https://notepad-plus-plus.org/community/topic/12467/keystroke-to-switch-focus-from-console-window-to-active-editor-tab, although I’ll only use this new way interactively (and will keep the existing SendKeys-based solution in my startup.py).

    I like it! :-D



  • The double-Windows-key works because when Notepad++ becomes the active application (second Windows logo keypress), focus is moved back to the current document tab if it was not there when N++ ceased being the active app. This seems to always be the case…

    So another easy(?) keyboard option is to hold Alt+Tab and at the same time tap Esc! :-D



  • Hi @scott-sumner and All,

    I did some tests and it happens that the double hit on the Windows logo key allows to put the focus back on the main editor windows, again, if a window can be anchored to the main editor windows, at its right, left, top or bottom side

    So, it concerns, from native N++, the Character Panel, Clipboard History, Search Results, Project, Folder as Workspace and the Function List windows, as well as most of plugin’s windows as, for instance, the Python or Lua console window !

    However, just note that if any of these “dockable” panels is not docked and is, simply, floating like a separate windows, the double hit on the Windows logo key does not allow, anymore, to have the focus back, on the main editor windows !

    Strangely, it does not work too, with the Document Map panel, which, however, can be anchored !

    Cheers,

    guy038


Log in to reply