Community
    • Login

    Finding available shortcut keys (originally "Where's the 'New Window' command?")

    Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
    53 Posts 7 Posters 5.8k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • EkopalypseE
      Ekopalypse @TBugReporter
      last edited by

      @TBugReporter

      The imports are needed to get access to the notepad++ (notepad) and scintilla (editor) objects, and for interaction with calls to the Windows library (ctypes).
      All of these objects are required.
      If you are concerned about re-importing something that is already used in another script, there is no reason to do so, as Python stores the imported objects internally in a dictionary and skips this step if the object is already loaded.

      We have to use another thread to start the shortcut mapper dialog because it blocks, otherwise it would wait until the dialog is closed and then we would not be able to collect all the information from the dialog.

      The easiest way to merge this with another script would be to rename the main function to something else, get rid of the notepad.new and editor.setText calls and then return the list of shortcuts.

      TBugReporterT 1 Reply Last reply Reply Quote 1
      • TBugReporterT
        TBugReporter @Ekopalypse
        last edited by TBugReporter

        @Ekopalypse said in Where’s the “New Window” command?:

        All of these objects are required.

        I figured that; I just wanted to get a better understanding of exactly why they’re required. (I never want to become that horrible programmer who blindly copies from other programs without taking the time to understand what the code is doing.)

        I don’t know if it’s differences in programming style, or just the fact that your script is doing all the heavy lifting, but @Alan-Kilborn’s is much easier for me to wrap my head around.

        We have to use another thread

        Okay, that makes sense.

        The easiest way to merge this with another script would be to rename the main function to something else, get rid of the notepad.new and editor.setText calls and then return the list of shortcuts.

        Actually, I probably want to keep them, but just massage the retrieved data differently than your script does - iterate over shortcuts, but build the output document non-sequentially. I’ll also need access to which tab and (for the “Main menu” tab) which Category each data item came from.

        EkopalypseE Alan KilbornA 2 Replies Last reply Reply Quote 1
        • Alan KilbornA
          Alan Kilborn @TBugReporter
          last edited by

          @TBugReporter said in Where’s the “New Window” command?:

          Although I must say I took a look at your desired format and I don’t really understand it.

          Did you scroll to the bottom?

          I didn’t! OK, it is clearer now.

          Mendella ReplacementM 1 Reply Last reply Reply Quote 0
          • Alan KilbornA
            Alan Kilborn @TBugReporter
            last edited by

            @TBugReporter said in Where’s the “New Window” command?:

            I’ve found a peculiar behavior using this. To reproduce:

            Invoke this command to create a new window.
            In the new window, use the Recent Files list to open a few files.
            Close the second window.
            Invoke the command again from the first window.
            Inspect the Recent Files list from this third window.

            Result: The files you opened in the second window are missing from the Recent Files list of the third (and subsequent) window(s). To get a full Recent Files list, I have to close the other window(s), close the first window, restart N++, and invoke New Window again.

            Something to remember when using multiple instances is that they don’t communicate well with each other. Another example is if you go into the Preferences and make a change, only that instance will know about the change. And, unless the instance where you made the change is exited last of all the instances, the change won’t be there when you run Notepad++ again. The reason for this is rather simple: When an instance of N++ exits, it writes its settings to disk. If another instance is still running, again, when it exits, it writes its settings to disk. If the settings happen to be different, the settings for the last one to write are preserved for the next clean run of the program.

            1 Reply Last reply Reply Quote 1
            • EkopalypseE
              Ekopalypse @TBugReporter
              last edited by

              @TBugReporter

              I never want to become that horrible programmer who blindly copies from other programs without taking the time to understand what the code is doing.

              Very commendable!

              … is much easier for me to wrap my head around.

              This is pretty basic Windows programming stuff, I’d say, but if you’re new to Windows programming, then let me briefly explain how this usually works.

              Whenever you want to interact with a GUI application in Windows, you need its ID, the HWND that is the handle of a window. You can get this by using user32.dll functions such as FindWindow and FindWindowEx.
              To communicate with the window, use functions like SendMessage.
              For example, TCM_GETITEMCOUNT is a message sent to a SysTabControl32 to query the number of available tabs.

              BGM_GETROWS is defined by Notepad++ itself.

              SetForegroundWindow is used to ensure that the following simulated keystrokes (keybd_event) are sent to the application they are intended for.

              1 Reply Last reply Reply Quote 1
              • Alan KilbornA
                Alan Kilborn @TBugReporter
                last edited by

                @TBugReporter said in Where’s the “New Window” command?:

                I don’t know if it’s differences in programming style, or just the fact that your (Eko) script is doing all the heavy lifting, but @Alan-Kilborn’s is much easier for me to wrap my head around.

                This is totally because Eko’s script IS doing the “heavy lifting”. My script is simple in comparison.

                When you see ctypes in a Python program, expect “heavy lifting”, “magic”, and “pixie dust” to be on display. :-)

                EkopalypseE 1 Reply Last reply Reply Quote 2
                • EkopalypseE
                  Ekopalypse @Alan Kilborn
                  last edited by

                  @Alan-Kilborn said in Where’s the “New Window” command?:

                  When you see ctypes in a Python program, expect “heavy lifting”, “magic”, and “pixie dust” to be on display. :-)

                  :-D and it works only during full moon and when you dance around a fire :-D

                  TBugReporterT 1 Reply Last reply Reply Quote 4
                  • TBugReporterT
                    TBugReporter @Ekopalypse
                    last edited by TBugReporter

                    I’m dancing as fast as I can (meaning “as my spare time allows”), but I’ve hit a snag. I want my script’s output to read the name of the tab where a given shortcut was found, but the descriptions I’ve found of how to do this for other languages either assume the existence of library functions in that language which I can’t find source code to, or else they dive headfirst into deep voodoo without a life jacket. :-}

                    I’m guessing I have to do something like

                    user32.SendMessageW(sys_tab_hwnd, TCM_GETITEMCOUNT, 0, 0)
                    

                    but send a different message, and figure out how to read the response. Any chance one of you could point me in a less random direction?

                    Also, given that this thread has drifted so far away from the original topic, is there any way I can change its title?

                    EkopalypseE 2 Replies Last reply Reply Quote 1
                    • EkopalypseE
                      Ekopalypse @TBugReporter
                      last edited by

                      @TBugReporter

                      I can take a look today after work (in 6-7 hours).

                      1 Reply Last reply Reply Quote 0
                      • guy038G
                        guy038
                        last edited by guy038

                        Hello, @tbugreporter ,

                        Regarding specifically the title changes, which title would you like to see ? As a moderator, I can modify it easily !

                        BR

                        guy038

                        TBugReporterT 1 Reply Last reply Reply Quote 1
                        • EkopalypseE
                          Ekopalypse @TBugReporter
                          last edited by

                          @TBugReporter

                          Found the time to try it out during my lunch break.

                          TCM_GETITEMW = (TCM_FIRST + 60)  # get the current tab message
                          TCIF_TEXT = 1  # flag to specify that we are only interested in pszText
                          
                          # define the storage that will contain the requested information.
                          class TCITEM(ctypes.Structure):
                              _fields_ = [('mask',        wintypes.UINT),
                                          ('dwState',     wintypes.DWORD),
                                          ('dwStateMask', wintypes.DWORD),
                                          ('pszText',     wintypes.LPWSTR),
                                          ('cchTextMax',  wintypes.INT),
                                          ('iImage',      wintypes.INT),
                                          ('lParam',      wintypes.LPARAM)]
                          
                          
                          pszText = ctypes.create_unicode_buffer(260)  # create a buffer to hold the tab text
                          tcitem = TCITEM()  # create an instance
                          tcitem.mask = TCIF_TEXT  # specify that we want to read the pszText field
                          tcitem.pszText = addressof(pszText)  # points to the tab text buffer 
                          tcitem.cchTextMax = len(pszText)  # length of buffer
                          pITEM = byref(tcitem)  # pointer to the concrete struct TCITEM 
                          
                          # within the for loop call
                          found = user32.SendMessageW(sys_tab_hwnd, TCM_GETITEMW, tab, pITEM)
                          if found:
                          	print(tcitem.pszText)
                          

                          Seems to work, let me know if anything is unclear.

                          TBugReporterT 1 Reply Last reply Reply Quote 2
                          • TBugReporterT
                            TBugReporter @guy038
                            last edited by

                            @guy038:

                            which title would you like to see ?

                            How about

                            Finding available shortcut keys (originally "Where's the 'New Window' command?")
                            

                            As a moderator, I can modify it easily !

                            TYVM!

                            @Ekopalypse:

                            Seems to work, let me know if anything is unclear.

                            Yes, that looks like the info I needed; now I just have to add it to the script.

                            TYVM to you too!

                            1 Reply Last reply Reply Quote 1
                            • TBugReporterT
                              TBugReporter @Ekopalypse
                              last edited by

                              @Ekopalypse

                              My latest sticking point:

                              NameError: global name 'byref' is not defined
                              
                              rdipardoR 1 Reply Last reply Reply Quote 0
                              • rdipardoR
                                rdipardo @TBugReporter
                                last edited by

                                NameError: global name 'byref' is not defined
                                

                                Try ctypes.byref instead.

                                1 Reply Last reply Reply Quote 1
                                • TBugReporterT
                                  TBugReporter
                                  last edited by

                                  Here’s a question from the “newless cluebie to Python” department:

                                  I’m currently struggling with errors like

                                  NameError: global name 'my_new_variable' is not defined
                                  

                                  I read that there’s a “global” statement that can help, but it doesn’t seem to work for me. Exactly where should this go? Or, is there another way I can rearrange the code that will avoid this?

                                  EkopalypseE 1 Reply Last reply Reply Quote 0
                                  • EkopalypseE
                                    Ekopalypse @TBugReporter
                                    last edited by

                                    @TBugReporter

                                    In the function in which it is used, suppose there is a code like this

                                    x = 42
                                    y = {'x': 42}
                                    
                                    def main():
                                        global x
                                        x += 1
                                        y['x'] += 1
                                        print(x)
                                        print(y)
                                        
                                    main()
                                    

                                    x needs to be defined as global, while it is not necessary for y, because it is a dict.

                                    1 Reply Last reply Reply Quote 2
                                    • TBugReporterT
                                      TBugReporter
                                      last edited by

                                      The pest is back! 😁 (I thank you in advance for your patience with me.)

                                      • Can I use PythonScript to display a Windows MessageBox? Can I create my own custom dialogs in Windows style?

                                      • How can I prematurely end my script (if something weird happens)? I found sys.exit(), but this apparently terminates all of Notepad++ along with the script.

                                      PeterJonesP TBugReporterT 2 Replies Last reply Reply Quote 1
                                      • PeterJonesP
                                        PeterJones @TBugReporter
                                        last edited by PeterJones

                                        @TBugReporter said in Finding available shortcut keys (originally “Where’s the ‘New Window’ command?”):

                                        • Can I use PythonScript to display a Windows MessageBox?

                                        Yes. 😉1

                                        Can I create my own custom dialogs in Windows style?

                                        Not easily. 😉2

                                        • How can I prematurely end my script (if something weird happens)? I found sys.exit(), but this apparently terminates all of Notepad++ along with the script.

                                        The best way I’ve found is to have a bunch of “if” processing so that it keeps on dumping out without running any of your code

                                        ----

                                        WinkNotes: 😉3

                                        😉1: notepad.messageBox()

                                        😉2: Alan tends to get around this by doing a bunch of free-form editor.input() notepad.prompt() calls, and then processing the text that the user types in to make the decisions. In theory, since PythonScript comes with the libraries necessary to access any of the win32 API functions: see plenty of examples in the forum with accessing SendMessage; searching the forum on the SendMessage from win32 API, and narrowing it down to @Ekopalypse’s posts, will get you some good examples pretty quickly – you would then have to extrapolate from that on how to access the various win32 API functions you want. But that said, I don’t know how practical it is to build a whole window using raw API calls – normally when programming win32 API, you would use resource files or equivalents, but I have no clue if you can define a resource file and easily give access to that resource file to the Python interpreter in PythonScript. (If you figure out a way, let me know, because I want to use that to reduce my library requirements in PerlScript some day.)

                                        😉3: wink notes are similar to footnotes, but made more annoying because I hid my actual answer inside the footnotes rather than in the main flow of the conversation

                                        TBugReporterT PeterJonesP 2 Replies Last reply Reply Quote 1
                                        • TBugReporterT
                                          TBugReporter @PeterJones
                                          last edited by TBugReporter

                                          @PeterJones said in Finding available shortcut keys (originally “Where’s the ‘New Window’ command?”):

                                          The best way I’ve found is to have a bunch of “if” processing

                                          If I have to resort to something like that, I’d use

                                          while True:
                                              pass
                                          

                                          instead. (Still an evil hack, but it seems slightly more elegant.)

                                          EkopalypseE 1 Reply Last reply Reply Quote 0
                                          • EkopalypseE
                                            Ekopalypse @TBugReporter
                                            last edited by Ekopalypse

                                            @TBugReporter

                                            With ctypes you have access to the Windows Api and can therefore do everything it offers. E.g. create a TaskDialog.

                                            39a6b14b-f03f-41a6-aca0-71952d2acaeb-image.png

                                            You can also build your own dialogs with the included Tkinter module, see for example the Formatter.py script from the demo directory.

                                            As for sys.exit, I found out that calling a “main” function and returning from that function serve the same purpose.

                                            def main():
                                                if x != 0:
                                                    return
                                            
                                            main()
                                            
                                            Alan KilbornA PeterJonesP 2 Replies Last reply Reply Quote 5
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors