Community
    • Login

    Can't rebind mouse buttons/scroll wheel

    Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
    13 Posts 4 Posters 501 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.
    • PeterJonesP
      PeterJones @mathlete2
      last edited by

      @Valour549 ,

      I just double-checked, and VK_LBUTTON, VK_RBUTTON, and VK_MBUTTON are sent as virtual keycodes (as are the X1 and X2 mouse buttons, so if you’ve got a mouse with extra buttons, they might be mappable as well), just the same as the other keyboard keys, so it should be doable. Scroll wheel events are processed differently (not with virtual keycodes, but with the WM_MOUSEWHEEL message), so I don’t think that Shortcut Mapper could process a scrollwheel up/down without (as far as I can tell) a huge redesign (since the Shortcut Mapper is currently limited to processing virtual keys).

      I recently expanded which keys were available to Notepad++, so I know where in the code to look, so I’ll run some experiments of trying to add the five mouse clicks (though not the scrollwheel).

      Since @mathlete2 was kind enough to check to see that no request currently exists, if you were to create an official feature request, then once I get my experiments working, I could attach a PR to that feature request. If you do make a request, make sure it links back to this discussion (and, if you can search the history of the forum to see if there have been other requests for allowing mouse buttons in the Shortcut Mapper; if so, link them); and once you’ve made the feature request, paste a link to that Issue back here in this discussion.

      Unfortunately, even if I am able to implement it, I cannot guarantee that the developer would accept my PR, so there is an element of risk, that the effort might be rejected.

      PeterJonesP 1 Reply Last reply Reply Quote 1
      • PeterJonesP
        PeterJones @PeterJones
        last edited by

        update: it didn’t end up being as easy as I’d hoped; on other real keys, it was just a matter of adding them to the available list for the shortcut mapper; when I tried the same with the mouse clicks (even unused ones, like the middle mouse button), nothing happened. So it’s going to be more involved than I hoped, so it will take more time, and I’m less hopeful that I have the skills to implement it. I won’t give up yet, but I thought I would manage expectations.

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

          @PeterJones said:

          So it’s going to be more involved than I hoped, so it will take more time…

          Possibly the scripted version (supporting the mouse wheel) will beat you to publication. :-)

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

            Here’s a scripted version of what the OP wants. It’s in two scripts, one is dependent on the other. First, the master script, MouseWheelHookDemo.py (the one that gets run):

            # -*- coding: utf-8 -*-
            
            #########################################
            #
            #  MouseWheelHookDemo (MWHD)
            #
            #########################################
            
            # note:
            #  This script was developed and tested under Python3 64-bit on unicode (non-ANSI) encoded data.
            #  It may work as-is using Python2 and/or ANSI-encoded data and/or 32-bits, but that would be incidental.
            
            # references:
            #  https://community.notepad-plus-plus.org/topic/26661
            #  for newbie info on PythonScripts, see https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript
            
            # to execute, use this in (e.g.) user startup.py:
            #  from MouseWheelHookDemo import MOUSE_WHEEL_HOOK_DEMO
            # another execution option would be to copy and then paste that line into the PythonScript console >>> box
            
            # note: if running via startup.py, need to make sure that "Initialisation" for "Python Script Configuration" is set to "ATSTARTUP" and not "LAZY".
            
            from Npp import *
            from ctypes import WinDLL
            from MsgHooker import MH as MsgHook
            
            WM_MOUSEWHEEL = 0x020A
            WM_SYSCOMMAND = 0x0112
            SC_KEYMENU = 0xF100
            VK_MENU = 0x12
            
            def HIWORD(value): return (value >> 16) & 0xFFFF
            def LOWORD(value): return value & 0xFFFF
            
            user32 = WinDLL('user32')
            
            def alt_held():
                return (user32.GetAsyncKeyState(VK_MENU) & 0x8000) != 0
            
            class MWHD(object):
            
                def __init__(self):
            
                    # these must be assigned to "self" variables so that they aren't garbage collected!
                    self.mh1 = MsgHook([ editor1.hwnd, editor2.hwnd ], self.editor_hook_func, [ WM_MOUSEWHEEL ])
                    self.mh2 = MsgHook([ notepad.hwnd ], self.notepad_hook_func, [ WM_SYSCOMMAND ])
            
                def editor_hook_func(self, hwnd, msg, wParam, lParam):
                    wheel_delta = HIWORD(wParam)
                    if wheel_delta > 0x7FFF: wheel_delta -= 0x1_0000
                    keys_down = LOWORD(wParam)
                    alt_down = alt_held()
                    if alt_down and keys_down == 0:
                        notepad.menuCommand(MENUCOMMAND.SEARCH_GOTONEXTFOUND if wheel_delta < 0 else MENUCOMMAND.SEARCH_GOTOPREVFOUND)
                        return False
                    return True
            
                # https://stackoverflow.com/questions/352270/how-to-cancel-the-system-key-down-state-in-windows
                def notepad_hook_func(self, hwnd, msg, wParam, lParam):
                    if (wParam & 0xFFF0) == SC_KEYMENU and lParam == 0: return False
                    return True
            
            MOUSE_WHEEL_HOOK_DEMO = MWHD()
            

            Next, the dependent script, MsgHooker.py:

            # -*- coding: utf-8 -*-
            
            import platform
            from ctypes import (WinDLL, WINFUNCTYPE)
            from ctypes.wintypes import (HWND, INT, LPARAM, UINT, WPARAM)
            
            user32 = WinDLL('user32')
            
            GWL_WNDPROC = -4  # used to set a new address for the window procedure
            
            LRESULT = LPARAM
            
            WndProcType = WINFUNCTYPE(
                LRESULT,  # return type
                HWND, UINT, WPARAM, LPARAM  # function arguments
                )
            
            running_32bit = platform.architecture()[0] == '32bit'
            SetWindowLong = user32.SetWindowLongW if running_32bit else user32.SetWindowLongPtrW
            SetWindowLong.restype = WndProcType
            SetWindowLong.argtypes = [ HWND, INT, WndProcType ]
            
            class MH(object):
            
                def __init__(self,
                        hwnd_to_hook_list,
                        hook_function,  # supplied hook_function must have args:  hwnd, msg, wparam, lparam
                                        #  and must return True/False (False means the function handled the msg)
                        msgs_to_hook_list=None,  # None means ALL msgs
                        ):
                    self.users_hook_fn = hook_function
                    self.msg_list = msgs_to_hook_list if msgs_to_hook_list is not None else []
                    self.new_wnd_proc_hook_for_SetWindowLong = WndProcType(self._new_wnd_proc_hook)  # the result of this call must be a self.xxx variable!
                    self.orig_wnd_proc_by_hwnd_dict = {}
                    for h in hwnd_to_hook_list:
                        self.orig_wnd_proc_by_hwnd_dict[h] = SetWindowLong(h, GWL_WNDPROC, self.new_wnd_proc_hook_for_SetWindowLong)
            
                def _new_wnd_proc_hook(self, hwnd, msg, wParam, lParam):
                    retval = True  # assume that this message will go unhandled (by us)
                    need_to_call_orig_proc = True
                    if len(self.msg_list) == 0 or msg in self.msg_list:
                        retval = self.users_hook_fn(hwnd, msg, wParam, lParam)
                        if not retval: need_to_call_orig_proc = False
                    if need_to_call_orig_proc:
                        retval = self.orig_wnd_proc_by_hwnd_dict[hwnd](hwnd, msg, wParam, lParam)
                    return retval
            
            1 Reply Last reply Reply Quote 1
            • Alan KilbornA Alan Kilborn referenced this topic on
            • Alan KilbornA
              Alan Kilborn
              last edited by

              Script compatibility note for PythonScript2:

              Find 0x1_0000 in the code and replace with 0x10000.

              1 Reply Last reply Reply Quote 1
              • V
                Valour549
                last edited by

                Thank you all for the replies.

                I have created a suggestion on github here.

                @Alan-Kilborn How do I use the scripts you created? Kind of a noob here so a step by step would be much appreciated 🙏

                PeterJonesP 1 Reply Last reply Reply Quote 0
                • PeterJonesP
                  PeterJones @Valour549
                  last edited by

                  @Valour549 said in Can't rebind mouse buttons/scroll wheel:

                  How do I use the scripts you created? Kind of a noob here

                  As it says near the top of @Alan-Kilborn’s first script,

                  for newbie info on PythonScripts, see https://community.notepad-plus-plus.org/topic/23039/faq-desk-how-to-install-and-run-a-script-in-pythonscript

                  1 Reply Last reply Reply Quote 0
                  • V
                    Valour549
                    last edited by

                    @Alan-Kilborn Thank you very much for the script, it’s working great.

                    @PeterJones Thank you for the FAQ guide. I found a typo I think. The highlight parts are meant to say step #4 right?

                    671fa878-d756-4d56-8e6b-67bf53015d46-image.png

                    PeterJonesP 1 Reply Last reply Reply Quote 1
                    • PeterJonesP
                      PeterJones @Valour549
                      last edited by

                      @Valour549 said in Can't rebind mouse buttons/scroll wheel:

                      I found a typo I think. The highlight parts are meant to say step #4 right?

                      Not a typo, but a “forgot to update”. Originally, the “install PythonScript” was “step #0”, which meant that the shortcuts were at step #3. At some point, that changed, and I forgot to update the cross-reference.

                      Fixed.

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

                        I must say that I like the functionality provided by the script myself, and I’ve started to use it. One thing I don’t particularly like, however, is not anything to do with the script, but rather how the NextResult (F4) and PreviousResult (Shift+F4) functionality works. After the last match is encountered, another F4 “wraps around” to the first match. It’s similar for Shift+F4. I find this annoying for reasons I’ve specified HERE. If other users feel the same way, and can publicly state so, maybe we can get an option to control this behavior.

                        1 Reply Last reply Reply Quote 0
                        • Alan KilbornA Alan Kilborn referenced this topic on
                        • First post
                          Last post
                        The Community of users of the Notepad++ text editor.
                        Powered by NodeBB | Contributors