• Login
Community
  • Login

Keyboard map chords (e.g., Ctrl+X Ctrl+C)

Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
16 Posts 5 Posters 4.5k 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.
  • B
    Bill Stewart
    last edited by Jan 2, 2019, 7:39 PM

    My apologies if this is a duplicate…

    Is it possible to map multi-key shortcuts like in EMACS or (I am dating myself) WordStar/Borland IDEs?

    For example, in WordStar, the keyboard shortcut to close a file is Ctrl+K Ctrl+Q (or Ctrl+K Q).

    If this is not possible, how do I make this a feature request?

    Thanks

    Bill

    M A 3 Replies Last reply Jan 2, 2019, 8:03 PM Reply Quote 0
    • M
      Meta Chuh moderator @Bill Stewart
      last edited by Jan 2, 2019, 8:03 PM

      @Bill-Stewart

      welcome to the notepad++ community.

      you can use multi key shortcuts, but you can’t use multi key sequences as shortcuts in notepad++.
      eg. you can set ctrl+q instead of ctrl+w to close a tab in settings > shortcut mapper, but you can’t trigger this shortcut with a key sequence like ctrl+k followed by ctrl+q.

      currently there is no dedicated place for feature requests like this one.
      but you can click the feature requests link from here
      which will lead you to the notepad++ issues page at github

      1 Reply Last reply Reply Quote 0
      • A
        Alan Kilborn @Bill Stewart
        last edited by Jan 2, 2019, 8:05 PM

        @Bill-Stewart said:

        or (I am dating myself) WordStar/Borland IDEs?

        You definitely are. But the fact that I know what you are talking about–what does that say about me? (but I’ve never heard this called “keyboard chords” before)

        how do I make this a feature request?

        Proper way is here: https://notepad-plus-plus.org/community/topic/15741/faq-desk-feature-request-or-bug-report
        But do you REALLY think such a feature request will be taken seriously? :) It’s 2019 for goodness sake…been waiting all year to use that line
        Note I have no decision-making power–that is just my feelings.

        Another option might be to do something in a scripting language. Watch the keyboard for the first keycombo, followed by something valid in the second keycombo (within a certain period of time maybe ?), then invoke the corresponding menu option, from the script. It would have to be something configured in code rather than something nicely set up in Shortcut Mapper… Some downsides but depending how much you want it… :)

        1 Reply Last reply Reply Quote 1
        • A
          Alan Kilborn @Bill Stewart
          last edited by Jan 2, 2019, 8:11 PM

          @Bill-Stewart

          BTW, your avatar dates you as well! :)

          1 Reply Last reply Reply Quote 0
          • B
            Bill Stewart
            last edited by Jan 2, 2019, 8:12 PM

            Thanks, I found the Github page.

            It’s 2019 for goodness sake…

            Don’t know what that’s got to do with anything. These kinds of keyboard shortcuts are supported in (3 examples) Visual Studio, Visual Studio Code, EMACS (and probably others also).

            A 1 Reply Last reply Jan 2, 2019, 8:22 PM Reply Quote 0
            • A
              Alan Kilborn @Bill Stewart
              last edited by Jan 2, 2019, 8:22 PM

              @Bill-Stewart said:

              Don’t know what that’s got to do with anything

              Maybe nothing. It was my attempt at humor. Because you hinted at this being something only “dinosaurs” (there I go with humor again) that remember Wordstar would find useful. It probably would have been better for you to have just cited the VS/VSCode/emacs examples in the first post, and dropped the Wordstar/Borland stuff. :) Certainly no offense to the people out there that love this type of keystroking. I still maintain the opinion that it probably isn’t widely enough used these days to be seriously considered as a Notepad++ change, but the feature request link is the way to go to pursue it. Good luck to ya.

              1 Reply Last reply Reply Quote 0
              • B
                Bill Stewart
                last edited by Jan 2, 2019, 11:01 PM

                For anyone interesting in viewing/voting for this feature:

                https://github.com/notepad-plus-plus/notepad-plus-plus/issues/5191

                1 Reply Last reply Reply Quote 1
                • M
                  Mikhail V
                  last edited by Mikhail V Jan 3, 2019, 5:15 PM Jan 3, 2019, 5:14 PM

                  I was the one who proposed adding input ‘modes’, like in Vim, which somewhat relates to what you describe. Namely I proposed to add a command mode, as an additional ‘page’ for keyboard input where keys do not type characters but rather can be bound to commands.
                  As it seems though, majority of users do not appretiate any departure from standard windows’ edit box behaviour, mainly because it is additional learning.
                  At the same time, adding such features requires changing the core parts of the editor — that means the change must be really worth the deal, and there hardly will ever be consensus what should be optimal input scheme.

                  As for me, I have found an excellent solution - Autohotkey app. This app is made exactly for input customization and automation. Also I have Pythonscript plugin in Npp, so using combinations of Autohotkey scripts and some Pythonscript plugin scripts, I can do almost any input customization.
                  E.g. I can have Vim-like command mode with only ~50 lines of Ahk script plus some Pythonscript code for visual feedback (it changes GUI colors in different modes).

                  So, to be honest, if you like experimenting with input, you could start with Autohotkey. It would be IMO more productive than hoping for this feature addition ;-). Just make up an more or less concrete idea of what input combination/scheme and functionality you seek for and try to implement in Autohotkey / Pythonscript plugin.

                  A 1 Reply Last reply Jan 3, 2019, 6:18 PM Reply Quote 2
                  • A
                    Alan Kilborn @Mikhail V
                    last edited by Jan 3, 2019, 6:18 PM

                    @Mikhail-V

                    Sounds interesting. How about posting a working example from your own efforts, both to illustrate the idea more fully and give a proof-of-concept.

                    M 1 Reply Last reply Jan 3, 2019, 7:37 PM Reply Quote 0
                    • M
                      Mikhail V @Alan Kilborn
                      last edited by Jan 3, 2019, 7:37 PM

                      @Alan-Kilborn

                      Sure, here is an examlpe AHK I use for toggling command mode with Capslock, and example commands respectively, comment and un-comment bound to q and w keys:

                      #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
                      SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
                      
                      CMode := false
                      
                      #If winActive("ahk_exe notepad++.exe") && WinActive("ahk_class Notepad++")
                      ; global hotkeys (active in all modes)
                      
                      capslock::
                      	if (CMode = false) {
                      		CMode := true
                      		send +{F11}			; execute visual feedback PS script inside NPP 
                      	} else {
                      		CMode :=  false
                      		send +{F12}			; execute visual feedback PS script inside NPP 
                      	}
                      	setCapslockState off	; keep capslock always off
                      return
                      
                      
                      #If CMode && WinActive("ahk_exe notepad++.exe") && WinActive("ahk_class Notepad++")
                      ; command mode hotkeys 
                      
                      ; comment
                      q:: 
                      	send ^q
                      return
                      
                      ; uncomment
                      w:: 
                      	send ^+q
                      return
                      
                      

                      Visual feedback is implemented in PS plugin scripts which are executed on Shift-F12 and Shift-F11 shortcuts (see send +{F12} above code).
                      E.g. this indicates command mode with blue folder column highlighting:

                      editor.setFoldMarginHiColour(1, (180, 200, 220))
                      editor.setFoldMarginColour(1, (180, 200, 220))
                      

                      And the second sets it back to my default color:

                      editor.setFoldMarginHiColour(1, (226,226,220))
                      editor.setFoldMarginColour(1, (226,226,220))
                      

                      As for OP idea with sequences - it is actually almost the same, if you want only 2-command sequences.
                      Just need to add code to get back to default mode from the hotkey in the second section.
                      If want support for more than 2 commands in a sequence, it will get more complicated of course.

                      A 1 Reply Last reply Jan 9, 2019, 1:28 PM Reply Quote 3
                      • Eko palypseE
                        Eko palypse
                        last edited by Eko palypse Jan 5, 2019, 12:12 AM Jan 5, 2019, 12:11 AM

                        That issue made be curious and I wanted to see if this could be solved with the PythonScript plugin in some way.
                        It is more of a proof of concept than a working solution but I thought it might be useful for some.
                        The script doesn’t prevent npp from executing registered shortcuts, if those are similar to the ones configured in the script.
                        Like if the script defines CTRL+K+L and you do have CTRL+K or CTRL+L mapped to some functions those get called,
                        as said - more of a proof of concept. But was really fun :-)

                        from __future__ import print_function
                        import ctypes
                        from ctypes.wintypes import DWORD, HRESULT, INT, WPARAM, LPARAM, HINSTANCE, HHOOK, BOOL, MSG
                        import threading
                        
                        user32 = ctypes.WinDLL('user32', use_last_error=True)
                        
                        def ErrorIfNone(result, func, arguments):
                            if result is None:
                                raise ctypes.WinError(ctypes.get_last_error())
                            else:
                                return result
                        
                        def ErrorIfZero(result, func, arguments):
                            if result == 0:
                                raise ctypes.WinError(ctypes.get_last_error())
                            else:
                                return result
                        
                        HOOKPROC = ctypes.WINFUNCTYPE(HRESULT, INT, WPARAM, LPARAM)
                        
                        SetWindowsHookEx = user32.SetWindowsHookExW
                        SetWindowsHookEx.argtypes = [INT, HOOKPROC, HINSTANCE, DWORD]
                        SetWindowsHookEx.restype = HHOOK
                        SetWindowsHookEx.errcheck = ErrorIfNone
                        
                        UnhookWindowsHookEx = user32.UnhookWindowsHookEx
                        UnhookWindowsHookEx.argtypes = [HHOOK]
                        UnhookWindowsHookEx.restype = BOOL
                        UnhookWindowsHookEx.errcheck = ErrorIfZero
                        
                        WH_KEYBOARD = 0x2
                        HC_ACTION = 0
                        
                        VK_SHIFT = 0x10
                        VK_CONTROL = 0x11
                        VK_MENU = 0x12
                        
                        MODIFIER_MAP = {VK_SHIFT: 'SHIFT',
                                        VK_CONTROL: 'CTRL',
                                        VK_MENU: 'ALT',}
                        
                        SHORTCUT_MAP = {'CTRL+L+K': lambda: print('do something\n'),
                                        'CTRL+K+L': lambda: print('do something other\n'),}
                        
                        class KEYLOGGER(threading.Thread):
                            def __init__(self):
                                threading.Thread.__init__(self)
                                self.hookHandle = None
                                self.hookFunction = None
                                self.keyCombo = ''
                                self.modifier = { VK_SHIFT:False, VK_CONTROL:False, VK_MENU:False }
                                self.modifier_keys = self.modifier.keys()
                                self.KEYUP = False
                                self.curr_class = ctypes.create_unicode_buffer(256)
                        
                            def register(self):
                                self.hookFunction = HOOKPROC(self.keyboardHook)
                                self.hookHandle = SetWindowsHookEx(WH_KEYBOARD, self.hookFunction, user32._handle, 0)
                        
                            def unregister(self):
                                if self.hookHandle is None:
                                    return
                                UnhookWindowsHookEx(self.hookHandle)
                                self.hookHandle = None
                        
                            def exec_shortcut(self, shortcut):
                                func = SHORTCUT_MAP.get(shortcut, None)
                                if func:
                                    func()
                        
                            def keyboardHook(self, nCode, wParam, lParam):
                                user32.GetClassNameW(user32.GetFocus(), self.curr_class, 256)
                                if self.curr_class.value == u'Scintilla' and nCode == HC_ACTION:
                        
                                    self.KEYUP = user32.GetKeyState(wParam) & 0x8000 == 0
                                    if wParam not in self.modifier_keys and self.KEYUP and any(self.modifier.values()):
                                        if 65 <= wParam <= 90:
                                            self.keyCombo += '+{}'.format(chr(wParam))
                        
                                    elif wParam in self.modifier_keys:
                                        if self.KEYUP:
                                            self.modifier[wParam] = False
                                            if not any(self.modifier.values()):
                                                self.exec_shortcut(self.keyCombo)
                                                self.keyCombo = ''
                                            else:
                                                self.keyCombo += '+{}'.format(MODIFIER_MAP[wParam])
                        
                                        else:
                                            if not any(self.modifier.values()):
                                                self.modifier[wParam] = True
                                                self.keyCombo = '{}'.format(MODIFIER_MAP[wParam])
                        
                                else:
                                    self.modifier = { VK_SHIFT:False, VK_CONTROL:False, VK_MENU:False }
                        
                                return user32.CallNextHookEx(_keyLogger.hookHandle, nCode, wParam, lParam)
                        
                            def run(self):
                                self.register()
                                msg = MSG()
                                user32.GetMessageW(ctypes.byref(msg), 0, 0, 0)
                        
                        
                        try:
                            _keyLogger.unregister()
                            del(_keyLogger)
                        except NameError:
                            _keyLogger = KEYLOGGER()
                            _keyLogger.start()
                        
                        A 1 Reply Last reply Jan 5, 2019, 12:36 AM Reply Quote 3
                        • A
                          Alan Kilborn @Eko palypse
                          last edited by Jan 5, 2019, 12:36 AM

                          @Eko palypse

                          Interestingly, that’s what I meant when I said above:

                          Another option might be to do something in a scripting language.

                          However, since then I’ve looked at the code I had that was somewhat similar to yours and it suffers the same problem: If a keycombo is mapped via Shortcut Mapper, I haven’t found a way to snag the keycombo for my own purpose and NOT have Shortcut Mapper decoding also see it. Too bad @ClaudiaFrank isn’t around any more because I’m sure she’d solve that one in a second! :)

                          To be more accurate, if a keycombo is mapped via Shortcut Mapper, then SM will see it and my code then won’t even get a chance at it.

                          Eko palypseE 1 Reply Last reply Jan 5, 2019, 1:07 PM Reply Quote 2
                          • Eko palypseE
                            Eko palypse @Alan Kilborn
                            last edited by Eko palypse Jan 5, 2019, 1:08 PM Jan 5, 2019, 1:07 PM

                            @Alan-Kilborn

                            if a keycombo is mapped via Shortcut Mapper, then SM will …

                            you are right - two cooks in a kitchen isn’t good.
                            If I’m right, the only way to intercept the message flow is to hook into the message queue,
                            which I should have done in first place anyway, but playing with some kind of keylogger sounded more exciting at that time.
                            And concerning the code, I have to admit, I got a lot of inspiration, sounds better than stealing,
                            doesn’t it, from @Claudia-Frank and @Scott-Sumner :-)
                            Maybe I will have a look at it some time later but for now I’m more interested in the the topic LSP,
                            as this has some benefits for me as well.

                            1 Reply Last reply Reply Quote 1
                            • A
                              Alan Kilborn @Mikhail V
                              last edited by Jan 9, 2019, 1:28 PM

                              @Mikhail-V

                              Thanks for posting the example, it really clarifies. I see it uses coloring of the fold margin. What about when you are working with files with no fold margin, example *.txt files? Then you don’t get the feedback about what “mode” you are in. :(

                              Wouldn’t it be better to color the line-number margin (presumes you have that turned on–side note: I’m always amazed that people post asking how to turn that OFF)? Of course, I can suggest that but I myself don’t see how one would change the color (via code) of that margin.

                              A 1 Reply Last reply Jan 9, 2019, 2:12 PM Reply Quote 0
                              • A
                                Alan Kilborn @Alan Kilborn
                                last edited by Alan Kilborn Jan 9, 2019, 2:14 PM Jan 9, 2019, 2:12 PM

                                @Alan-Kilborn said:

                                but I myself don’t see how one would change the color (via code) of that margin.

                                I must correct myself. I DO see how to do it, half-an-hour later:

                                editor.styleSetBack(STYLESCOMMON.LINENUMBER, (255, 0, 0))

                                will turn the background of the line-number margin a rather glaring red, for example.

                                M 1 Reply Last reply Jan 9, 2019, 6:49 PM Reply Quote 0
                                • M
                                  Mikhail V @Alan Kilborn
                                  last edited by Jan 9, 2019, 6:49 PM

                                  @Alan-Kilborn said:

                                  editor.styleSetBack(STYLESCOMMON.LINENUMBER, (255, 0, 0))

                                  will turn the background of the line-number margin a rather glaring red, for example.

                                  Yes, changing the line number color is actually better solution in general and it can be better visible.
                                  I’ve used folder margin from the beginning and just was too lazy to experiment further :)
                                  BTW, if you want to make permanently visible folder margin in any file, it can be done with Pythonscript plugin via “startup.py ” script.

                                  1. Disable folder margin:
                                    Settings - > Preference -> Editing : set “Folder margin style” to “None”
                                  2. Add e.g. this to startup.py :
                                  editor.setMarginWidthN (2, 16)				# set folder margin to 16 pixel
                                  editor.markerDefine (MARKEROUTLINE.FOLDEROPEN,  MARKERSYMBOL.ARROWDOWN)
                                  editor.markerDefine (MARKEROUTLINE.FOLDERSUB,  MARKERSYMBOL.EMPTY)
                                  editor.markerDefine (MARKEROUTLINE.FOLDERTAIL,  MARKERSYMBOL.EMPTY)
                                  ...
                                  

                                  then Restart Npp. So can even define custom marker symbols or just set them all to EMPTY.
                                  see:
                                  https://www.scintilla.org/ScintillaDoc.html#Markers
                                  http://npppythonscript.sourceforge.net/docs/latest/enums.html#markeroutline

                                  1 Reply Last reply Reply Quote 1
                                  1 out of 16
                                  • First post
                                    1/16
                                    Last post
                                  The Community of users of the Notepad++ text editor.
                                  Powered by NodeBB | Contributors