Community
    • Login

    Editor right-click, outside current text selection, lose this selection

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    35 Posts 6 Posters 10.3k 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.
    • László BotkaL
      László Botka
      last edited by

      For example I select the text, that I perhaps want to Copy/Cut, then I watch the text moving the mouse until find the text, where I want to copy to, right click Copy/Cut, left click at the desired text on the screen where I want to copy, and right click Paste.

      This is hard enough to describe for me, but easy to do.

      It gives me a lot of freedom, I don’t have to issue “Copy”, only when and where it is needed, so I don’t overwrite the clipboard possibly unnecessarily.

      Naturally right-clicking inside the selection area works already, nobody have to work on it - I understand this thinking.

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

        Regardless, its a Scintilla characteristic, not a Notepad++ characteristic…

        BTW, I have no clue as to what this means:

        I select the text, that I perhaps want to Copy/Cut, then I watch the text moving the mouse until find the text, where I want to copy to, right click Copy/Cut, left click at the desired text on the screen where I want to copy, and right click Paste.

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

          Hello, @frying-pan, @alan-kilborn, @lászló-botka and All,

          @lászló-botka, you said :

          For example I select the text, that I perhaps want to Copy/Cut, then I watch the text moving the mouse until find the text, where I want to copy to, right click Copy/Cut, left click at the desired text on the screen where I want to copy, and right click Paste.

          OK, I see ! Personally, I would have used, both, keyboard and mouse :

          • Selection of text to be copied elsewhere

          • Hit on the Ctrl + C shortcut to place selection into clipboard

          • Move of the mouse to the other location where you want to paste the selection

          • Left mouse click to specify the new location of the caret

          • Right mouse click to get the context menu

          • Left mouse click on the Paste option


          However, to be honest, I’m more a “keyboard-gestures” man than a “mouse-gestures” one ;-))

          Best regards

          guy038

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

            Okay, so after reading @guy038’s response to:

            I select the text, that I perhaps want to Copy/Cut, then I watch the text moving the mouse until find the text, where I want to copy to, right click Copy/Cut, left click at the desired text on the screen where I want to copy, and right click Paste.

            it helped me to understand it, I think.

            If I were doing it that way, I’d have zero confidence that the source block I was copying/cutting was still selected. Much better to have it onscreen (which the current Notepad++ enforces) when copying/cutting it.

            But I agree with @guy038 about mouse-vs-keyboard, and here are the actions compared:

            mouse :

            • move hand from keyboard to mouse (this is a text editor after all)
            • right click
            • choose copy
            • return hand to keyboard (this is a text editor after all)

            keyboard :

            • press ctrl+c

            Even mouse purists (if there are any) would have a hard time arguing with the effort involved. :-)

            1 Reply Last reply Reply Quote 0
            • EkopalypseE
              Ekopalypse @frying-pan
              last edited by

              @frying-pan

              Note, that you only set the hook for one scintilla message queue but
              I assume you want it to have for both, don’t you?

              Beside that everything is personal coding preferences, just be carefully to call it once.

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

                Hi, @alan-kilborn,

                You said :

                BTW, I have no clue as to what this means:

                To my mind, here are the different operations, described by @lászló-botka :

                • First, you select, with the mouse, some text to be pasted elsewhere

                • Then you search for the location where to paste the selection. moving the vertical bar of the window up/down to reach the new location ( the selection, which may be out of sight, is still active )

                • Now, as you are around the desired location, you right-click to get the context menu

                • Then, you left-click on the Copy option, which places present selection into clipboard ( This is the step where Notepad and Notepad++ behaviors differ ! )

                • Now, you left-click at the location where you want the contents of clipboard to be inserted

                • Again, you right-click to get the context menu

                • Finally, you left-click and choose the Paste option

                Best Regards,

                guy038

                Alan KilbornA László BotkaL 2 Replies Last reply Reply Quote 2
                • Alan KilbornA
                  Alan Kilborn @guy038
                  last edited by

                  @guy038 said in Editor right-click, outside current text selection, lose this selection:

                  To my mind, here are the different operations, described by @lászló-botka :

                  Yes, I understood this from your earlier clarification. Maybe you had this reply in progress before seeing my earlier reply.

                  I just still find it odd, but to each his own.

                  1 Reply Last reply Reply Quote 0
                  • László BotkaL
                    László Botka @guy038
                    last edited by

                    @guy038 exactly, thank you for making it clear.

                    Alan KilbornA 1 Reply Last reply Reply Quote 2
                    • Alan KilbornA
                      Alan Kilborn @László Botka
                      last edited by

                      @László-Botka

                      I see, it works in Notepad, Wordpad, Ultraedit, although doesn’t work in Winword.

                      Another notable is Visual Studio 2019, where it works exactly like Notepad++ does.

                      1 Reply Last reply Reply Quote 1
                      • László BotkaL
                        László Botka
                        last edited by

                        I have a rarely used editor installed, Pspad, and it works again as Winword, Notepad ++, Visual Studio 2019.

                        I see no reason why one program behaves this way and the other that way. Maybe it’s occasional, it works the way it just did, or the way it was natural, simple for the programmer in the development tool.

                        Since I use Firefox a lot, it’s natural for me to select something, and if I move the mouse by any reason or accidentally, and then do a right click, the selection remains.

                        Alan KilbornA 1 Reply Last reply Reply Quote 2
                        • Alan KilbornA
                          Alan Kilborn @László Botka
                          last edited by

                          @László-Botka said in Editor right-click, outside current text selection, lose this selection:

                          have a rarely used editor installed, Pspad

                          PsPad is cool! :-)

                          I like to think of it this way: If I select something with the mouse, and I want to drag-n-drop-move-it, I can’t just point anywhere and click-drag, I have to point to the selected text first. So right-click-copy is analogous.

                          But yes, points and all views about this are well-taken. Good discussions are what this forum is about.

                          1 Reply Last reply Reply Quote 2
                          • frying-panF
                            frying-pan
                            last edited by

                            I wonder if explaining why it is very useful to me is needed.

                            first example : (I copy a lot between different tabs and different applications)
                            Some text is selected in a notepad++ tab, or any application window, that I need to copy repeatedly.
                            I activate this tab or window with ctrl+tab/alt+tab, right-click anywhere and ‘copy’,
                            go back to the other app and right-click anywhere and ‘paste’.
                            So, I do not have to point every time the selection or the caret for copying/pasting.

                            second example :
                            I select some text in a notepad++ tab with the mouse, and immediatly right-click to copy it.
                            If I have moved just a pixel farther than the selection, then I lose the selection and can not copy it.

                            Added benefit : Since I can right-click anywhere, I do not have the context-menu appearing above the selection,
                            so I can check my selection is good…

                            indeed Microsoft Visual Studio (when editing Microsoft Word macro) is one of the infamous selection-looser
                            Internet Explorer 11 also…

                            ===

                            Here is the improved code

                            • code has been hardened against errors
                            • the hook still can not be removed (*see below the code why),
                              but now can be “de-activated”/“re-activated” by re-running the script
                            • now hooks all scintilla windows (so incuding the notepad++ second view when splitted)
                            • added : SHIFT + double left mouse click -> select text from click point until next space/space-like chars

                            (sorry the two functions SHIFT+double-left-click and right-click can not be “de-activated” separately,
                            I think a dialog prompt and two separate variables set by console.editor.SetProperty would do that)

                            # PythonScript which hooks mouse clicks (WndProc HOOK on Scintilla windows)
                            # * SHIFT + double left mouse click : select text from click point until next space/space-like chars : \s
                            # * right mouse click : prevent right-click from moving the caret and losing current text selection
                            # re-run the script to de-activate/re_activate the hook
                            # Tested on NPP 64 bits (NOT tested on 32 Bits but could be compatible), /!\ this file uses TABS for indent
                            
                            from Npp import *
                            
                            import platform
                            import ctypes
                            from ctypes import wintypes
                            import datetime
                            from datetime import datetime
                            
                            s_script_name			= "Perso_ScintWndProc_Hook"
                            s_hook_name				= "Scint_Mouse_Click_Hook"
                            s_editorprop_regdone	= "SCINTWNDPROCHOOK_DONE"
                            s_editorprop_active		= "SCINTWNDPROCHOOK_ACTIVE"
                            s_true					= "TRUE"
                            
                            GWL_WNDPROC = -4				# used to set a new address for the windows procedure
                            I_VK_SHIFT		= 0x10			# SHIFT virtual key code
                            I_VK_CONTROL	= 0x11			# CONTROL virtual key code
                            I_VK_ALT		= 0x12			# ALT virtual key code
                            KSTATE_ISDOWN = 0x8000			# key pressed
                            WM_LBUTTONDBLCLK	= 0x0203	# double left mouse click window message
                            WM_RBUTTONDOWN		= 0x0204	# right mouse click window message
                            
                            LRESULT = wintypes.LPARAM
                            WndProcType = ctypes.WINFUNCTYPE(LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
                            
                            # window message hook functions
                            CallWindowProc = ctypes.windll.user32.CallWindowProcW
                            CallWindowProc.restype = LRESULT
                            CallWindowProc.argtypes = [WndProcType, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM]
                            
                            x86 = platform.architecture()[0] == "32bit"
                            if x86:
                            	SetWindowLong = ctypes.windll.user32.SetWindowLongW
                            else:
                            	SetWindowLong = ctypes.windll.user32.SetWindowLongPtrW
                            SetWindowLong.restype = WndProcType
                            SetWindowLong.argtypes = [wintypes.HWND, wintypes.INT, WndProcType]
                            # end of window message hook functions
                            
                            EnumWindowsProc				= ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
                            EnumWindows					= ctypes.windll.user32.EnumWindows
                            EnumChildWindows			= ctypes.windll.user32.EnumChildWindows
                            RealGetWindowClass			= ctypes.windll.user32.RealGetWindowClassW
                            GetWindowThreadProcessId	= ctypes.windll.user32.GetWindowThreadProcessId
                            GetCurrentProcessId			= ctypes.windll.kernel32.GetCurrentProcessId
                            GetLastError				= ctypes.windll.kernel32.GetLastError
                            SetLastError				= ctypes.windll.kernel32.SetLastError
                            
                            GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState # used to check if a modifier key is pressed
                            
                            class C_Scint_Mouse_Click_Hook(): # hook class
                            	# class constructor
                            	def __init__(self):
                            		def Enum_Window_Hwnd(hwnd, lParam):
                            			arr_enum_window_hwnd.append(hwnd)
                            			return True
                            
                            		s_npp_class		= u"Notepad++"
                            		s_scint_class	= u"Scintilla"
                            
                            		self.arr_scint_hwnd = []
                            		self.npp_win_hwnd = 0
                            
                            		i_cur_pid = GetCurrentProcessId()
                            
                            		arr_enum_window_hwnd = []
                            		EnumWindows(EnumWindowsProc(Enum_Window_Hwnd), 0)
                            		# enum all class="Notepad++" NPP window handles
                            		buff = ctypes.create_unicode_buffer(len(s_npp_class) + 1 + 1)
                            		for win_hwnd in arr_enum_window_hwnd:
                            			RealGetWindowClass(win_hwnd, buff, len(s_npp_class) + 1 + 1)
                            			if buff.value == s_npp_class:
                            				# check that found NPP window handle is owned by current process, stop at the first found
                            				ci_win_pid = wintypes.DWORD(0)
                            				GetWindowThreadProcessId(win_hwnd, ctypes.pointer(ci_win_pid))
                            				if i_cur_pid == ci_win_pid.value:
                            					self.npp_win_hwnd = win_hwnd
                            					break
                            		if self.npp_win_hwnd == 0:
                            			return
                            
                            		del arr_enum_window_hwnd[:]
                            		EnumChildWindows(self.npp_win_hwnd, EnumWindowsProc(Enum_Window_Hwnd), 0)
                            		# enum all class="Scintilla" window handles, childs of NPP window
                            		# get all of them in arr_scint_hwnd (at least all existing ones at that time)
                            		buff = ctypes.create_unicode_buffer(len(s_scint_class) + 1 + 1)
                            		for win_hwnd in arr_enum_window_hwnd:
                            			RealGetWindowClass(win_hwnd, buff, len(s_scint_class) + 1 + 1)
                            			if buff.value == s_scint_class:
                            				self.arr_scint_hwnd.append(win_hwnd)
                            
                            	def RegHook(self):															# function to register the hook on all found Scintilla windows
                            		s_npp_class		= u"Notepad++"
                            		s_scint_class	= u"Scintilla"
                            
                            		if (self.npp_win_hwnd == 0 or len(self.arr_scint_hwnd) == 0):			# abort if no NPP handle or no Scintilla handle
                            			return
                            
                            		self.NewWndProc = WndProcType(self.MyWndProc)							# get the address of our own WndProc
                            
                            		self.arr_scint_oldwndproc = []
                            		s_list = "\t" + "Found " + str(len(self.arr_scint_hwnd)) + " " + s_scint_class + " Handle / WindowProc"
                            		for i in range(0, len(self.arr_scint_hwnd)):
                            			win_hwnd = self.arr_scint_hwnd[i]
                            			SetLastError(0)
                            			oldwndproc = SetWindowLong(win_hwnd, GWL_WNDPROC, self.NewWndProc)	# register and store oldwndproc addresses in arr_scint_oldwndproc
                            			i_apierr = GetLastError()
                            			if i_apierr == 0:
                            				self.arr_scint_oldwndproc.append(oldwndproc)
                            				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + str(oldwndproc)
                            			else:
                            				del self.arr_scint_hwnd[i]
                            				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + "NO WindowProc, NOT hooked"
                            		print "\t" + s_npp_class + " Handle = " + hex(self.npp_win_hwnd) + "\n" + s_list
                            
                            	def MyWndProc(self, hWnd, msg, wParam, lParam):							# our own WndProc function receives windows messages
                            		oldwndproc = 0
                            		for i in range(0, len(self.arr_scint_hwnd)):
                            			if self.arr_scint_hwnd[i] == hWnd:								# target hWnd found at index i in arr_scint_hwnd
                            				oldwndproc = self.arr_scint_oldwndproc[i]					# corresponding oldwndproc is picked in arr_scint_oldwndproc
                            				break
                            		if oldwndproc == 0:													# fatal error ! should not happen...
                            			print "\t" + s_hook_name + " Fatal error ! oldwndproc = 0"
                            			notepad.messageBox(s_hook_name + " Fatal error ! oldwndproc = 0", s_script_name)
                            			return 0
                            
                            		if (msg != WM_LBUTTONDBLCLK and msg != WM_RBUTTONDOWN):				# if NOT mouse hooked messages : abort
                            			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                            		if console.editor.getProperty(s_editorprop_active) != s_true:		# if hook de-activated : abort
                            			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                            
                            		b_shift_down	= ((GetAsyncKeyState(I_VK_SHIFT)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                            		b_ctrl_down		= ((GetAsyncKeyState(I_VK_CONTROL)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                            		b_alt_down		= ((GetAsyncKeyState(I_VK_ALT)		& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                            		if (b_shift_down and b_ctrl_down and b_alt_down):					# if SHIFT and CONTROL and ALT down : unregister
                            			self.UnRegHook()
                            			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                            
                            		if (msg == WM_LBUTTONDBLCLK and b_shift_down and not b_ctrl_down and not b_alt_down):
                            			self.ExtendSelToSpaceLikeChars()								# extend selection from the clicked point to the space-like chars
                            		elif (msg == WM_RBUTTONDOWN and not b_shift_down and not b_ctrl_down and not b_alt_down):
                            			dummy = 0														# do nothing
                            		else:
                            			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                            
                            		#res = "DEBUG " + s_hook_name
                            		#res = res + " Message = " + hex(msg) + " to hWnd = " + hex(hWnd)
                            		#res = res + " Forwarded To oldwndproc = " + str(oldwndproc)
                            		#print res + " At " + str(datetime.now())
                            		return CallWindowProc(oldwndproc, hWnd, 0, 0, 0)					# nullify the mouse hooked messages
                            
                            	def ExtendSelToSpaceLikeChars(self):
                            		# space-like chars are space/tab/carriage return/line feed/form feed... [\t\n\x0B\f\r\x20\x85\xA0\x{2028}\x{2029}]
                            		editor.searchAnchor()
                            		i_start = editor.searchPrev(FINDOPTION.REGEXP, "\s")
                            		i_start = i_start + 1
                            		if i_start < 0:
                            			i_start = 0
                            		i_end = editor.searchNext(FINDOPTION.REGEXP, "\s")
                            		if i_end < 0:
                            			i_end = editor.getTextLength()
                            		editor.setSel(i_start, i_end)
                            
                            print "[" + s_script_name + " starts]"
                            if console.editor.getProperty(s_editorprop_regdone) != s_true:
                            	console.editor.setProperty(s_editorprop_regdone, s_true)
                            	console.editor.setProperty(s_editorprop_active, s_true)
                            	o_scint_mouse_click_hook = C_Scint_Mouse_Click_Hook()	# create an instance of hook class
                            	o_scint_mouse_click_hook.RegHook()						# set up the mouse hook
                            	print "\t" + s_hook_name + " registered and ACTIVATED (re-run script to toggle the hook)"
                            else:
                            	if console.editor.getProperty(s_editorprop_active) != s_true:
                            		console.editor.setProperty(s_editorprop_active, s_true)
                            		print "\t" + s_hook_name + " RE-ACTIVATED (re-run script to toggle the hook)"
                            		notepad.messageBox(s_hook_name + " RE-ACTIVATED\n(re-run script to toggle the hook)", s_script_name)
                            	else:
                            		console.editor.setProperty(s_editorprop_active, "")
                            		print "\t" + s_hook_name + " de-activated (re-run script to toggle the hook)"
                            		notepad.messageBox(s_hook_name + " de-activated\n(re-run script to toggle the hook)", s_script_name)
                            
                            

                            *Breaking the hook chain :
                            If a hook is set by

                            self.NewWndProc = WndProcType(self.MyWndProc)
                            oldwndproc = SetWindowLong(win_hwnd, GWL_WNDPROC, self.NewWndProc)
                            

                            and then removed by

                            SetWindowLong(win_hwnd, GWL_WNDPROC, oldwndproc)
                            

                            that breaks the hook chain if there is more than 1 hook.

                            original WndProc funcA > hooked by MyWndProc funcB > hooked by MyOtherWndProc funcC
                            if funcB hook is removed, than funcC will not receive any message after that, and will not be aware of it

                            Some more sophisticated hook api could solve that problem but I don’t know them.
                            I chose the easiest way, which is to “de-activate” my hook by just telling him to do nothing,
                            except silently forwarding the window message to the the next WndProc (oldwndproc).
                            This way my “de-activated” hook does nothing but does not break the hook chain.

                            Alan KilbornA frying-panF 2 Replies Last reply Reply Quote 2
                            • Alan KilbornA
                              Alan Kilborn @frying-pan
                              last edited by

                              @frying-pan said in Editor right-click, outside current text selection, lose this selection:

                              I wonder if explaining why it is very useful to me is needed.

                              Not needed, but often I give people that at first seem to want odd things a “hard time” about it, and it draws them out into explaining/justifying their need.

                              Future readers that come along then get the whole story, and maybe don’t dismiss something that could really be of use.

                              I think you have done a good job of that, as well as solving your own problem with the script. Nicely done!

                              frying-panF 1 Reply Last reply Reply Quote 1
                              • frying-panF
                                frying-pan @Alan Kilborn
                                last edited by frying-pan

                                @Alan-Kilborn

                                Well, I would not have made Notepad++ my default text editor, if I couldn’t have solved the right-click question.

                                It’s the first reason I bothered to install PythonScript and learn this syntax (while I’m only accustomed to Pascal/VB/VBS/AutoIt)

                                And otherwise I use PSPad for its Project features, Notepad++ session and workspace are not as featured.
                                PSPad is mostly missing code wrapping (if > endif, etc…)

                                1 Reply Last reply Reply Quote 1
                                • frying-panF
                                  frying-pan
                                  last edited by

                                  Oops, I forgot to delete 3 lines of old code (at line 141 of the script). But I can’t modify any more the previous post.

                                  So the code updated without the bug :

                                  # PythonScript which hooks mouse clicks (WndProc HOOK on Scintilla windows)
                                  # * SHIFT + double left mouse click : select text from click point until next space/space-like chars : \s
                                  # * right mouse click : prevent right-click from moving the caret and losing current text selection
                                  # re-run the script to de-activate/re-activate the hook
                                  # Tested on NPP 64 bits (NOT tested on 32 Bits but could be compatible), /!\ this file uses TABS for indent
                                  
                                  from Npp import *
                                  
                                  import platform
                                  import ctypes
                                  from ctypes import wintypes
                                  import datetime
                                  from datetime import datetime
                                  
                                  s_script_name			= "Perso_ScintWndProc_Hook"
                                  s_hook_name				= "Scint_Mouse_Click_Hook"
                                  s_editorprop_regdone	= "SCINTWNDPROCHOOK_DONE"
                                  s_editorprop_active		= "SCINTWNDPROCHOOK_ACTIVE"
                                  s_true					= "TRUE"
                                  
                                  GWL_WNDPROC = -4				# used to set a new address for the windows procedure
                                  I_VK_SHIFT		= 0x10			# SHIFT virtual key code
                                  I_VK_CONTROL	= 0x11			# CONTROL virtual key code
                                  I_VK_ALT		= 0x12			# ALT virtual key code
                                  KSTATE_ISDOWN = 0x8000			# key pressed
                                  WM_LBUTTONDBLCLK	= 0x0203	# double left mouse click window message
                                  WM_RBUTTONDOWN		= 0x0204	# right mouse click window message
                                  
                                  LRESULT = wintypes.LPARAM
                                  WndProcType = ctypes.WINFUNCTYPE(LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
                                  
                                  # window message hook functions
                                  CallWindowProc = ctypes.windll.user32.CallWindowProcW
                                  CallWindowProc.restype = LRESULT
                                  CallWindowProc.argtypes = [WndProcType, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM]
                                  
                                  x86 = platform.architecture()[0] == "32bit"
                                  if x86:
                                  	SetWindowLong = ctypes.windll.user32.SetWindowLongW
                                  else:
                                  	SetWindowLong = ctypes.windll.user32.SetWindowLongPtrW
                                  SetWindowLong.restype = WndProcType
                                  SetWindowLong.argtypes = [wintypes.HWND, wintypes.INT, WndProcType]
                                  # end of window message hook functions
                                  
                                  EnumWindowsProc				= ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
                                  EnumWindows					= ctypes.windll.user32.EnumWindows
                                  EnumChildWindows			= ctypes.windll.user32.EnumChildWindows
                                  RealGetWindowClass			= ctypes.windll.user32.RealGetWindowClassW
                                  GetWindowThreadProcessId	= ctypes.windll.user32.GetWindowThreadProcessId
                                  GetCurrentProcessId			= ctypes.windll.kernel32.GetCurrentProcessId
                                  GetLastError				= ctypes.windll.kernel32.GetLastError
                                  SetLastError				= ctypes.windll.kernel32.SetLastError
                                  
                                  GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState # used to check if a modifier key is pressed
                                  
                                  class C_Scint_Mouse_Click_Hook(): # hook class
                                  	# class constructor
                                  	def __init__(self):
                                  		def Enum_Window_Hwnd(hwnd, lParam):
                                  			arr_enum_window_hwnd.append(hwnd)
                                  			return True
                                  
                                  		s_npp_class		= u"Notepad++"
                                  		s_scint_class	= u"Scintilla"
                                  
                                  		self.arr_scint_hwnd = []
                                  		self.npp_win_hwnd = 0
                                  
                                  		i_cur_pid = GetCurrentProcessId()
                                  
                                  		arr_enum_window_hwnd = []
                                  		EnumWindows(EnumWindowsProc(Enum_Window_Hwnd), 0)
                                  		# enum all class="Notepad++" NPP window handles
                                  		buff = ctypes.create_unicode_buffer(len(s_npp_class) + 1 + 1)
                                  		for win_hwnd in arr_enum_window_hwnd:
                                  			RealGetWindowClass(win_hwnd, buff, len(s_npp_class) + 1 + 1)
                                  			if buff.value == s_npp_class:
                                  				# check that found NPP window handle is owned by current process, stop at the first found
                                  				ci_win_pid = wintypes.DWORD(0)
                                  				GetWindowThreadProcessId(win_hwnd, ctypes.pointer(ci_win_pid))
                                  				if i_cur_pid == ci_win_pid.value:
                                  					self.npp_win_hwnd = win_hwnd
                                  					break
                                  		if self.npp_win_hwnd == 0:
                                  			return
                                  
                                  		del arr_enum_window_hwnd[:]
                                  		EnumChildWindows(self.npp_win_hwnd, EnumWindowsProc(Enum_Window_Hwnd), 0)
                                  		# enum all class="Scintilla" window handles, childs of NPP window
                                  		# get all of them in arr_scint_hwnd (at least all existing ones at that time)
                                  		buff = ctypes.create_unicode_buffer(len(s_scint_class) + 1 + 1)
                                  		for win_hwnd in arr_enum_window_hwnd:
                                  			RealGetWindowClass(win_hwnd, buff, len(s_scint_class) + 1 + 1)
                                  			if buff.value == s_scint_class:
                                  				self.arr_scint_hwnd.append(win_hwnd)
                                  
                                  	def RegHook(self):															# function to register the hook on all found Scintilla windows
                                  		s_npp_class		= u"Notepad++"
                                  		s_scint_class	= u"Scintilla"
                                  
                                  		if (self.npp_win_hwnd == 0 or len(self.arr_scint_hwnd) == 0):			# abort if no NPP handle or no Scintilla handle
                                  			return
                                  
                                  		self.NewWndProc = WndProcType(self.MyWndProc)							# get the address of our own WndProc
                                  
                                  		self.arr_scint_oldwndproc = []
                                  		s_list = "\t" + "Found " + str(len(self.arr_scint_hwnd)) + " " + s_scint_class + " Handle / WindowProc"
                                  		for i in range(0, len(self.arr_scint_hwnd)):
                                  			win_hwnd = self.arr_scint_hwnd[i]
                                  			SetLastError(0)
                                  			oldwndproc = SetWindowLong(win_hwnd, GWL_WNDPROC, self.NewWndProc)	# register and store oldwndproc addresses in arr_scint_oldwndproc
                                  			i_apierr = GetLastError()
                                  			if i_apierr == 0:
                                  				self.arr_scint_oldwndproc.append(oldwndproc)
                                  				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + str(oldwndproc)
                                  			else:
                                  				del self.arr_scint_hwnd[i]
                                  				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + "NO WindowProc, NOT hooked"
                                  		print "\t" + s_npp_class + " Handle = " + hex(self.npp_win_hwnd) + "\n" + s_list
                                  
                                  	def MyWndProc(self, hWnd, msg, wParam, lParam):							# our own WndProc function receives windows messages
                                  		oldwndproc = 0
                                  		for i in range(0, len(self.arr_scint_hwnd)):
                                  			if self.arr_scint_hwnd[i] == hWnd:								# target hWnd found at index i in arr_scint_hwnd
                                  				oldwndproc = self.arr_scint_oldwndproc[i]					# corresponding oldwndproc is picked in arr_scint_oldwndproc
                                  				break
                                  		if oldwndproc == 0:													# fatal error ! should not happen...
                                  			print "\t" + s_hook_name + " Fatal error ! oldwndproc = 0"
                                  			notepad.messageBox(s_hook_name + " Fatal error ! oldwndproc = 0", s_script_name)
                                  			return 0
                                  
                                  		if (msg != WM_LBUTTONDBLCLK and msg != WM_RBUTTONDOWN):				# if NOT mouse hooked messages : abort
                                  			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                  		if console.editor.getProperty(s_editorprop_active) != s_true:		# if hook de-activated : abort
                                  			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                  
                                  		b_shift_down	= ((GetAsyncKeyState(I_VK_SHIFT)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                  		b_ctrl_down		= ((GetAsyncKeyState(I_VK_CONTROL)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                  		b_alt_down		= ((GetAsyncKeyState(I_VK_ALT)		& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                  
                                  		if (msg == WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and not(b_alt_down)):
                                  			self.ExtendSelToSpaceLikeChars()								# extend selection from the clicked point to the space-like chars
                                  		elif (msg == WM_RBUTTONDOWN and not(b_shift_down) and not(b_ctrl_down) and not(b_alt_down)):
                                  			dummy = 0														# do nothing
                                  		else:
                                  			return CallWindowProc(oldwndproc, hWnd, msg, wParam, lParam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                  
                                  		#res = "DEBUG " + s_hook_name
                                  		#res = res + " Message = " + hex(msg) + " to hWnd = " + hex(hWnd)
                                  		#res = res + " Forwarded To oldwndproc = " + str(oldwndproc)
                                  		#print res + " At " + str(datetime.now())
                                  		return CallWindowProc(oldwndproc, hWnd, 0, 0, 0)					# nullify the mouse hooked messages
                                  
                                  	def ExtendSelToSpaceLikeChars(self):
                                  		# space-like chars are space/tab/carriage return/line feed/form feed... [\t\n\x0B\f\r\x20\x85\xA0\x{2028}\x{2029}]
                                  		editor.searchAnchor()
                                  		i_start = editor.searchPrev(FINDOPTION.REGEXP, "\s")
                                  		i_start = i_start + 1
                                  		if i_start < 0:
                                  			i_start = 0
                                  		i_end = editor.searchNext(FINDOPTION.REGEXP, "\s")
                                  		if i_end < 0:
                                  			i_end = editor.getTextLength()
                                  		editor.setSel(i_start, i_end)
                                  
                                  print "[" + s_script_name + " starts]"
                                  if console.editor.getProperty(s_editorprop_regdone) != s_true:
                                  	console.editor.setProperty(s_editorprop_regdone, s_true)
                                  	console.editor.setProperty(s_editorprop_active, s_true)
                                  	o_scint_mouse_click_hook = C_Scint_Mouse_Click_Hook()	# create an instance of hook class
                                  	o_scint_mouse_click_hook.RegHook()						# set up the mouse hook
                                  	print "\t" + s_hook_name + " registered and ACTIVATED (re-run script to toggle the hook)"
                                  else:
                                  	if console.editor.getProperty(s_editorprop_active) != s_true:
                                  		console.editor.setProperty(s_editorprop_active, s_true)
                                  		print "\t" + s_hook_name + " RE-ACTIVATED (re-run script to toggle the hook)"
                                  		notepad.messageBox(s_hook_name + " RE-ACTIVATED\n(re-run script to toggle the hook)", s_script_name)
                                  	else:
                                  		console.editor.setProperty(s_editorprop_active, "")
                                  		print "\t" + s_hook_name + " de-activated (re-run script to toggle the hook)"
                                  		notepad.messageBox(s_hook_name + " de-activated\n(re-run script to toggle the hook)", s_script_name)
                                  
                                  
                                  1 Reply Last reply Reply Quote 0
                                  • frying-panF
                                    frying-pan @frying-pan
                                    last edited by frying-pan

                                    This post is deleted!
                                    1 Reply Last reply Reply Quote 0
                                    • frying-panF
                                      frying-pan
                                      last edited by

                                      Code update, probably the last for this script, since I have all the keyboard + mouse shortcuts I need.

                                      • corrected one bug :
                                        (in case of a Scintilla window hook failure, the list of hooked WndProcs was incorrectly shortened and enumerated)
                                      • cleaned the code
                                      • added more keyboard + mouse shortcuts :
                                        • SHIFT + double-left-click : select from clicked point the whole variable name : alphanumeric with _ and . (dot)
                                        • CTRL + SHIFT + double-left-click : select from clicked point the whole bracket content : () [] {}, from left in case of mismatch
                                        • ALT + SHIFT + double-left-click : select from clicked point the whole quote content : “” ‘’, from left in case of mismatch
                                        • ALT + right-click : select from clicked point until space/space-like characters are met : space/tab/cr/lf/formfeed/vtab etc…
                                        • right-click : prevent right-click from moving the caret and losing current text selection
                                      • added options to disable each shortcut separately (these options values must be edited in the script file)

                                      note : my code rendering would be better if I could set up the real tabs to appear as 4 chars wide on this forum
                                      (I prefer to have 4 chars wide tabs in Notepad++ but this forum render them as 8 chars wide)

                                      note: since the code is too long to be loaded in one post, it will posted in two chunks.

                                      Code chunk 1/2:

                                      # PythonScript which hooks mouse clicks (WndProc HOOK on Scintilla windows)
                                      # Tested on Notepad++ 64 bits (NOT tested on 32 Bits but could be compatible) /!\ this file uses TABS for indent /!\
                                      	# SHIFT + double-left-click			: select from clicked point the whole variable name : alphanumeric with _ and . (dot)
                                      	# CTRL + SHIFT + double-left-click	: select from clicked point the whole bracket content : () [] {}, from left in case of mismatch
                                      	# ALT + SHIFT + double-left-click	: select from clicked point the whole quote content : "" '', from left in case of mismatch
                                      	# ALT + right-click					: select from clicked point until space/space-like characters are met : space/tab/cr/lf/formfeed/vtab etc...
                                      	# right-click						: prevent right-click from moving the caret and losing current text selection
                                      # re-run the script to de-activate/re-activate the whole hook (re-running the script will also apply new *options values*)
                                      # change the *options values* (just below) to choose which mouse hooks will be active
                                      
                                      # *options values* : set value to INTEGER 1 to have the feature enabled (any OTHER INTEGER value will DISABLE it)
                                      i_feature_shift_double_left_click			= 1
                                      i_feature_control_shift_double_left_click	= 1
                                      i_feature_alt_shift_double_left_click		= 1
                                      i_feature_alt_right_click					= 1
                                      i_feature_right_click						= 1
                                      i_message_box_warnings						= 1	# if disabled, no message box will pop on registering hook error,
                                      												# or when toggling the hook (console messages will still occur)
                                      # end of *options values*
                                      
                                      from Npp import *
                                      
                                      import platform
                                      import ctypes
                                      from ctypes import wintypes
                                      import datetime
                                      from datetime import datetime
                                      
                                      s_script_name	= "Perso_ScintWndProc_Hook"
                                      s_hook_name		= "Scint_Mouse_Click_Hook"
                                      
                                      s_editorprop_regdone		= "SCINTWNDPROC_HOOK_DONE"
                                      s_editorprop_active			= "SCINTWNDPROC_HOOK_ACTIVE"
                                      s_editorprop_sdlc_active	= "SCINTWNDPROC_SDLC_ACTIVE"
                                      s_editorprop_csdlc_active	= "SCINTWNDPROC_CSDLC_ACTIVE"
                                      s_editorprop_asdlc_active	= "SCINTWNDPROC_ASDLC_ACTIVE"
                                      s_editorprop_arc_active		= "SCINTWNDPROC_ARC_ACTIVE"
                                      s_editorprop_rc_active		= "SCINTWNDPROC_RC_ACTIVE"
                                      s_true						= "TRUE"
                                      
                                      s_reruntogglehook	= "Re-run the script to toggle the whole hook"
                                      s_willapplynewopt	= "This will also apply new *options values* saved in the script file"
                                      s_feature_sdlc_off	= "* Feature SHIFT + double-left-click is DISABLED by script option"
                                      s_feature_csdlc_off	= "* Feature CTRL + SHIFT + double-left-click is DISABLED by script option"
                                      s_feature_asdlc_off	= "* Feature ALT + SHIFT + double-left-click is DISABLED by script option"
                                      s_feature_arc_off	= "* Feature ALT + right-click is DISABLED by script option"
                                      s_feature_rc_off	= "* Feature right-click is DISABLED by script option"
                                      
                                      GWL_WNDPROC = -4				# used to set a new address for the windows procedure
                                      I_VK_SHIFT		= 0x10			# SHIFT virtual key code
                                      I_VK_CONTROL	= 0x11			# CONTROL virtual key code
                                      I_VK_ALT		= 0x12			# ALT virtual key code
                                      KSTATE_ISDOWN = 0x8000			# key pressed
                                      WM_LBUTTONDBLCLK	= 0x0203	# mouse double-left-click window message
                                      WM_RBUTTONDOWN		= 0x0204	# mouse right-click down window message
                                      WM_RBUTTONUP		= 0x0205	# mouse right-click up window message
                                      
                                      LRESULT = wintypes.LPARAM
                                      WndProcType = ctypes.WINFUNCTYPE(LRESULT, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM)
                                      
                                      # window message hook functions
                                      CallWindowProc = ctypes.windll.user32.CallWindowProcW
                                      CallWindowProc.restype = LRESULT
                                      CallWindowProc.argtypes = [WndProcType, wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM]
                                      
                                      x86 = platform.architecture()[0] == "32bit"
                                      if x86:
                                      	SetWindowLong = ctypes.windll.user32.SetWindowLongW
                                      else:
                                      	SetWindowLong = ctypes.windll.user32.SetWindowLongPtrW
                                      SetWindowLong.restype = WndProcType
                                      SetWindowLong.argtypes = [wintypes.HWND, wintypes.INT, WndProcType]
                                      # end of window message hook functions
                                      
                                      EnumWindowsProc				= ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
                                      EnumWindows					= ctypes.windll.user32.EnumWindows
                                      EnumChildWindows			= ctypes.windll.user32.EnumChildWindows
                                      GetAsyncKeyState			= ctypes.windll.user32.GetAsyncKeyState
                                      RealGetWindowClass			= ctypes.windll.user32.RealGetWindowClassW
                                      GetWindowThreadProcessId	= ctypes.windll.user32.GetWindowThreadProcessId
                                      GetCurrentProcessId			= ctypes.windll.kernel32.GetCurrentProcessId
                                      SetLastError				= ctypes.windll.kernel32.SetLastError
                                      GetLastError				= ctypes.windll.kernel32.GetLastError
                                      
                                      class C_Scint_Mouse_Click_Hook():
                                      	# class constructor
                                      	def __init__(self):
                                      		self.arr_scint_hwnd = []
                                      		self.arr_scint_oldwndproc = []
                                      
                                      	# function to register the hook on all found Scintilla windows
                                      	def RegHook(self):
                                      		def Enum_Window_Hwnd(hwnd, lparam):
                                      			arr_enum_window_hwnd.append(hwnd)
                                      			return True
                                      
                                      		s_npp_class		= u"Notepad++"
                                      		s_scint_class	= u"Scintilla"
                                      
                                      		i_cur_pid = GetCurrentProcessId()
                                      		npp_win_hwnd = None
                                      
                                      		arr_enum_window_hwnd = []
                                      		EnumWindows(EnumWindowsProc(Enum_Window_Hwnd), 0)
                                      		# get all class="Notepad++" top_level NPP windows handle
                                      		buff = ctypes.create_unicode_buffer(len(s_npp_class) + 1 + 1)
                                      		for win_hwnd in arr_enum_window_hwnd:
                                      			RealGetWindowClass(win_hwnd, buff, len(s_npp_class) + 1 + 1)
                                      			if buff.value == s_npp_class:
                                      				# check if each NPP window handle is owned by current process, stop at the first found
                                      				ci_win_pid = wintypes.DWORD(0)
                                      				GetWindowThreadProcessId(win_hwnd, ctypes.pointer(ci_win_pid))
                                      				if i_cur_pid == ci_win_pid.value:
                                      					npp_win_hwnd = win_hwnd
                                      					break
                                      		if npp_win_hwnd is None:
                                      			print "\t" + s_npp_class + " window NOT found ! NO hook !"
                                      			return False
                                      		print "\t" + s_npp_class + " Handle = " + hex(npp_win_hwnd)
                                      
                                      		del arr_enum_window_hwnd[:]
                                      		EnumChildWindows(npp_win_hwnd, EnumWindowsProc(Enum_Window_Hwnd), 0)
                                      		# get all class="Scintilla" windows handle, childs of NPP window, in arr_scint_hwnd
                                      		# (at least all existing Scintilla windows at that time, should include primary and secondary views)
                                      		buff = ctypes.create_unicode_buffer(len(s_scint_class) + 1 + 1)
                                      		for win_hwnd in arr_enum_window_hwnd:
                                      			RealGetWindowClass(win_hwnd, buff, len(s_scint_class) + 1 + 1)
                                      			if buff.value == s_scint_class:
                                      				self.arr_scint_hwnd.append(win_hwnd)
                                      
                                      		# get the address of our own WndProc
                                      		self.newWndProc = WndProcType(self.MyWndProc)
                                      
                                      		# register the hook for each window present in arr_scint_hwnd
                                      		s_list = "\t" + "Found " + str(len(self.arr_scint_hwnd)) + " " + s_scint_class + " Handle / WindowProc"
                                      		i_index = 0
                                      		while i_index < len(self.arr_scint_hwnd):
                                      			win_hwnd = self.arr_scint_hwnd[i_index]
                                      			# register hook and store oldwndproc addresses in arr_scint_oldwndproc
                                      			SetLastError(0)
                                      			oldwndproc = SetWindowLong(win_hwnd, GWL_WNDPROC, self.newWndProc)
                                      			i_apierr = GetLastError()
                                      			if i_apierr == 0:
                                      				self.arr_scint_oldwndproc.append(oldwndproc)
                                      				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + str(oldwndproc)
                                      				i_index = i_index + 1
                                      			else:
                                      				del self.arr_scint_hwnd[i_index]
                                      				s_list = s_list + "\n" + "\t\t" + hex(win_hwnd) + " / " + "NO WindowProc ! NOT hooked !"
                                      		print s_list
                                      		if len(self.arr_scint_hwnd) == 0:
                                      			print "\t" + s_scint_class + " window(s) or WindowProc(s) NOT found ! NO hook !"
                                      			return False
                                      		return True
                                      
                                      	def MyWndProc(self, hwnd, msg, wparam, lparam):							# our own WndProc function receives windows messages
                                      		oldwndproc = None
                                      		for i in range(0, len(self.arr_scint_hwnd)):
                                      			if self.arr_scint_hwnd[i] == hwnd:								# target hwnd found at index i in arr_scint_hwnd
                                      				oldwndproc = self.arr_scint_oldwndproc[i]					# corresponding oldwndproc is picked in arr_scint_oldwndproc
                                      				break
                                      		if oldwndproc is None:												# fatal error ! should not happen...
                                      			print "\t" + s_hook_name + " Fatal error ! Hooked WndProc NOT found !"
                                      			notepad.messageBox(s_hook_name + " Fatal error ! Hooked WndProc NOT found !", s_script_name, MESSAGEBOXFLAGS.ICONEXCLAMATION)
                                      			return 0
                                      
                                      		if (msg != WM_LBUTTONDBLCLK and msg != WM_RBUTTONDOWN and msg != WM_RBUTTONUP): # if NOT in mouse hooked messages : abort
                                      			return CallWindowProc(oldwndproc, hwnd, msg, wparam, lparam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                      		if console.editor.getProperty(s_editorprop_active) != s_true:		# if hook de-activated : abort
                                      			return CallWindowProc(oldwndproc, hwnd, msg, wparam, lparam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                      
                                      		b_shift_down	= ((GetAsyncKeyState(I_VK_SHIFT)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                      		b_ctrl_down		= ((GetAsyncKeyState(I_VK_CONTROL)	& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                      		b_alt_down		= ((GetAsyncKeyState(I_VK_ALT)		& KSTATE_ISDOWN) == KSTATE_ISDOWN)
                                      
                                      		if (console.editor.getProperty(s_editorprop_sdlc_active) == "1" and \
                                      				msg == WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and not(b_alt_down)):
                                      			self.ExtendSel_AlphaNumUnderscoreDot()							# select from clicked point the whole variable name
                                      		if (console.editor.getProperty(s_editorprop_csdlc_active) == "1" and \
                                      				msg == WM_LBUTTONDBLCLK and b_shift_down and b_ctrl_down and not(b_alt_down)):
                                      			self.ExtendSel_BracketContent()									# select from clicked point the whole bracket content
                                      		if (console.editor.getProperty(s_editorprop_asdlc_active) == "1" and \
                                      				msg == WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and b_alt_down):
                                      			self.ExtendSel_Quotes()											# select from clicked point the whole quote content
                                      		elif (console.editor.getProperty(s_editorprop_arc_active) == "1" and \
                                      				msg == WM_RBUTTONUP and not(b_shift_down) and not(b_ctrl_down) and b_alt_down):
                                      			self.ExtendSel_SpaceSpaceLike()
                                      		elif (console.editor.getProperty(s_editorprop_rc_active) == "1" and \
                                      				msg == WM_RBUTTONDOWN and not(b_shift_down) and not(b_ctrl_down) and not(b_alt_down)):
                                      			dummy = 0														# do nothing
                                      		else:
                                      			return CallWindowProc(oldwndproc, hwnd, msg, wparam, lparam)	# -> IMPORTANT pass other msg to NPP, otherwise will block NPP
                                      
                                      		#res = "DEBUG " + s_hook_name
                                      		#res = res + " Message = " + hex(msg) + " to hwnd = " + hex(hwnd)
                                      		#res = res + " Forwarded To oldwndproc = " + str(oldwndproc)
                                      		#print res + " At " + str(datetime.now())
                                      		return CallWindowProc(oldwndproc, hwnd, 0, 0, 0)					# nullify the mouse hooked messages
                                      
                                      
                                      1 Reply Last reply Reply Quote 1
                                      • frying-panF
                                        frying-pan
                                        last edited by

                                        Code chunk 2/2:

                                        	def FindBorderBiDir(self, i_start, s_pattern):
                                        		i_text_len = editor.getTextLength()
                                        		t_search = editor.findText(FINDOPTION.REGEXP, i_start, 0, s_pattern)
                                        		if t_search is None:
                                        			i_left = -1
                                        		else:
                                        			i_left = t_search[0]
                                        		t_search = editor.findText(FINDOPTION.REGEXP, i_start, i_text_len, s_pattern)
                                        		if t_search is None:
                                        			i_right = i_text_len
                                        		else:
                                        			i_right = t_search[0]
                                        		return (i_left, i_right)
                                        
                                        	def ExtendSel_SpaceSpaceLike(self):
                                        		s_pattern = "\s"
                                        
                                        		i_caret_pos = editor.getCurrentPos()
                                        		i_start	= editor.getSelectionStart()
                                        		i_end	= editor.getSelectionEnd()
                                        
                                        		t_border = self.FindBorderBiDir(i_caret_pos, s_pattern)
                                        		i_left	= t_border[0] + 1
                                        		i_right	= t_border[1]
                                        		if i_left < i_right:
                                        			editor.setSel(i_left, i_right)
                                        		else:
                                        			editor.setSel(i_start, i_end)
                                        
                                        	def ExtendSel_AlphaNumUnderscoreDot(self):
                                        		s_pattern = "[^\w_.]"
                                        
                                        		i_caret_pos = editor.getCurrentPos()
                                        		i_start	= editor.getSelectionStart()
                                        		i_end	= editor.getSelectionEnd()
                                        
                                        		t_border = self.FindBorderBiDir(i_caret_pos, s_pattern)
                                        		i_left	= t_border[0] + 1
                                        		i_right	= t_border[1]
                                        		if i_left < i_right:
                                        			editor.setSel(i_left, i_right)
                                        		else:
                                        			editor.setSel(i_start, i_end)
                                        
                                        	def ExtendSel_Quotes(self):
                                        		i_text_len = editor.getTextLength()
                                        		i_caret_pos = editor.getCurrentPos()
                                        		i_start	= editor.getSelectionStart()
                                        		i_end	= editor.getSelectionEnd()
                                        
                                        		t_search_prev_single = editor.findText(0, i_caret_pos, 0, "'")
                                        		t_search_next_single = editor.findText(0, i_caret_pos, i_text_len, "'")
                                        		t_search_prev_double = editor.findText(0, i_caret_pos, 0, chr(34))
                                        		t_search_next_double = editor.findText(0, i_caret_pos, i_text_len, chr(34))
                                        
                                        		i_left	= None
                                        		i_right	= None
                                        		if ((t_search_prev_single is None) or (t_search_next_single is None)):
                                        			if (not(t_search_prev_double is None) and not(t_search_next_double is None)):
                                        				i_left	= t_search_prev_double[0] + 1
                                        				i_right	= t_search_next_double[0]
                                        		elif ((t_search_prev_double is None) or (t_search_next_double is None)):
                                        			if (not(t_search_prev_single is None) and not(t_search_next_single is None)):
                                        				i_left	= t_search_prev_single[0] + 1
                                        				i_right	= t_search_next_single[0]
                                        		elif t_search_prev_single[0] < t_search_prev_double[0]:
                                        				i_left	= t_search_prev_double[0] + 1
                                        				i_right	= t_search_next_double[0]
                                        		elif t_search_prev_double[0] < t_search_prev_single[0]:
                                        				i_left	= t_search_prev_single[0] + 1
                                        				i_right	= t_search_next_single[0]
                                        		if (not(i_left is None) and not(i_right is None)):
                                        			editor.setSel(i_left, i_right)
                                        		else:
                                        			editor.setSel(i_start, i_end)
                                        
                                        	def ExtendSel_BracketContent(self):
                                        		def SearchOrphan(i_start, i_end, s_pattern_brackets):
                                        			if i_start == i_end:
                                        				return None
                                        
                                        			if i_start < i_end: b_forward = True
                                        			else: b_forward = False
                                        
                                        			i_par = 0; i_sqr = 0; i_cur = 0
                                        			i_pos = i_start
                                        			while True:
                                        				t_search = editor.findText(FINDOPTION.REGEXP, i_pos, i_end, s_pattern_brackets)
                                        				if t_search is None:
                                        					return None
                                        
                                        				i_pos = t_search[0]
                                        				s_char = editor.getTextRange(i_pos, i_pos + 1)
                                        				if		s_char == "(": i_par += 1
                                        				elif	s_char == ")": i_par -= 1
                                        				elif	s_char == "[": i_sqr += 1
                                        				elif	s_char == "]": i_sqr -= 1
                                        				elif	s_char == "{": i_cur += 1
                                        				elif	s_char == "}": i_cur -= 1
                                        
                                        				if b_forward:
                                        					if (i_par < 0 or i_sqr < 0 or i_cur < 0): break
                                        				else:
                                        					if (i_par > 0 or i_sqr > 0 or i_cur > 0): break
                                        				if b_forward: i_pos = i_pos + 1
                                        			return (i_pos, s_char)
                                        
                                        		i_text_len = editor.getTextLength()
                                        		i_caret_pos = editor.getCurrentPos()
                                        		i_start	= editor.getSelectionStart()
                                        		i_end	= editor.getSelectionEnd()
                                        
                                        		s_pattern_par = "\(\)"
                                        		s_pattern_sqr = "\[\]"
                                        		s_pattern_cur = "\{\}"
                                        		s_pattern_brackets = "[" + s_pattern_par + s_pattern_sqr + s_pattern_cur + "]"
                                        
                                        		i_left	= None
                                        		i_right	= None
                                        		while True:
                                        			t_orphan_back = SearchOrphan(i_caret_pos, 0, s_pattern_brackets)
                                        			if t_orphan_back is None: break
                                        
                                        			s_char = t_orphan_back[1]
                                        			if		s_char == "(": s_pattern = "[" + s_pattern_par + "]"
                                        			elif	s_char == "[": s_pattern = "[" + s_pattern_sqr + "]"
                                        			elif	s_char == "{": s_pattern = "[" + s_pattern_cur + "]"
                                        			t_orphan_forward = SearchOrphan(i_caret_pos, i_text_len, s_pattern)
                                        			if not(t_orphan_forward is None):
                                        				i_left	= t_orphan_back[0] + 1
                                        				i_right	= t_orphan_forward[0]
                                        				break
                                        
                                        			if		s_char == "(": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_par, "")
                                        			elif	s_char == "[": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_sqr, "")
                                        			elif	s_char == "{": s_pattern_brackets = s_pattern_brackets.replace(s_pattern_cur, "")
                                        			if s_pattern_brackets == "[]": break
                                        		if (not(i_left is None) and not(i_right is None)):
                                        			editor.setSel(i_left, i_right)
                                        		else:
                                        			editor.setSel(i_start, i_end)
                                        	# end of class
                                        
                                        s_opt_info = ""
                                        if i_feature_shift_double_left_click			!= 1: s_opt_info = s_opt_info + "\t" + s_feature_sdlc_off + "\n"
                                        if i_feature_control_shift_double_left_click	!= 1: s_opt_info = s_opt_info + "\t" + s_feature_csdlc_off + "\n"
                                        if i_feature_alt_shift_double_left_click		!= 1: s_opt_info = s_opt_info + "\t" + s_feature_asdlc_off + "\n"
                                        if i_feature_alt_right_click					!= 1: s_opt_info = s_opt_info + "\t" + s_feature_arc_off + "\n"
                                        if i_feature_right_click						!= 1: s_opt_info = s_opt_info + "\t" + s_feature_rc_off + "\n"
                                        if not(s_opt_info == ""): s_opt_info = s_opt_info[:-1]
                                        console.editor.setProperty(s_editorprop_sdlc_active,	str(i_feature_shift_double_left_click))
                                        console.editor.setProperty(s_editorprop_csdlc_active,	str(i_feature_control_shift_double_left_click))
                                        console.editor.setProperty(s_editorprop_asdlc_active,	str(i_feature_alt_shift_double_left_click))
                                        console.editor.setProperty(s_editorprop_arc_active,		str(i_feature_alt_right_click))
                                        console.editor.setProperty(s_editorprop_rc_active,		str(i_feature_right_click))
                                        
                                        print "[" + s_script_name + " starts]"
                                        if console.editor.getProperty(s_editorprop_regdone) != s_true:
                                        	console.editor.setProperty(s_editorprop_active, s_true)
                                        	o_scint_mouse_click_hook = C_Scint_Mouse_Click_Hook()	# create an instance of the hook class
                                        	b_reg = o_scint_mouse_click_hook.RegHook()				# register the hook on all found Scintilla windows
                                        	if b_reg:
                                        		console.editor.setProperty(s_editorprop_regdone, s_true)
                                        		print "\t" + s_hook_name + " registered and activated (" + s_reruntogglehook + ")"
                                        		if not(s_opt_info == ""): print s_opt_info
                                        	else:
                                        		if not(s_opt_info == ""): print s_opt_info
                                        		print "\t" + s_hook_name + " registering failed"
                                        		if i_message_box_warnings == 1:
                                        			notepad.messageBox(s_hook_name + " registering failed", s_script_name, MESSAGEBOXFLAGS.ICONSTOP)
                                        else:
                                        	if console.editor.getProperty(s_editorprop_active) != s_true:
                                        		console.editor.setProperty(s_editorprop_active, s_true)
                                        		print "\t" + s_hook_name + " re-activated (" + s_reruntogglehook + ")"
                                        		if not(s_opt_info == ""): print s_opt_info
                                        		if i_message_box_warnings == 1:
                                        			notepad.messageBox( \
                                        				s_hook_name + " re-activated\n\n" + s_reruntogglehook + "\n" + s_willapplynewopt + "\n" + s_opt_info, \
                                        				s_script_name, MESSAGEBOXFLAGS.ICONINFORMATION)
                                        	else:
                                        		console.editor.setProperty(s_editorprop_active, "")
                                        		print "\t" + s_hook_name + " DE-ACTIVATED (" + s_reruntogglehook + ")"
                                        		if not(s_opt_info == ""): print s_opt_info
                                        		if i_message_box_warnings == 1:
                                        			notepad.messageBox( \
                                        				s_hook_name + " DE-ACTIVATED\n\n" + s_reruntogglehook + "\n" + s_willapplynewopt + "\n" + s_opt_info, \
                                        				s_script_name, MESSAGEBOXFLAGS.ICONEXCLAMATION)
                                        
                                        
                                        1 Reply Last reply Reply Quote 1
                                        • frying-panF
                                          frying-pan
                                          last edited by

                                          Hey ! the forum changed the line 313 of my uploaded code

                                          line 313 was uploaded as :
                                          (I must replace \ by BKL to have it displayed)
                                          s_pattern_sqr = “BKL[BKL]”
                                          but is displayed without the \ as :
                                          s_pattern_sqr = “[]”

                                          which breaks the ‘CTRL + SHIFT + double-left-click’ feature : select brackets content : () [] {}

                                          having compared the whole uploaded code with my original code there should no other error
                                          (I used a simple file compare utility to do that : ExamDiff)

                                          So there is a bug in the text parser of the forum :
                                          the preview is ok but the final post has lost the backslashes

                                          Michael VincentM Alan KilbornA 2 Replies Last reply Reply Quote 1
                                          • Michael VincentM
                                            Michael Vincent @frying-pan
                                            last edited by

                                            @frying-pan
                                            Wow, that’s quite a script. Maybe post to GitHub or a Gist and then link from here to that post?

                                            Cheers.

                                            frying-panF 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors