Example #1
0
class C_Scint_Mouse_Click_Hook():
    # class constructor
    def __init__(self, s_script_name, s_hook_name, i_feature_on,
                 s_editorprop_hook_on, dic_features):
        import platform
        import ctypes
        from ctypes import wintypes
        import time
        self.time = time

        from Perso__Lib_Window import C_Get_NPPScintilla_Wins
        from Perso__Lib_Edit import C_Extend_Sel_From_Caret
        self.o_get_nppscintilla_wins = C_Get_NPPScintilla_Wins()
        self.o_extend_sel_from_caret = C_Extend_Sel_From_Caret()

        self.HookDone = False
        self.script_name = s_script_name
        self.hook_name = s_hook_name
        self.feature_on = i_feature_on
        self.editorprop_hook_on = s_editorprop_hook_on
        self.editorprop_sdlc_on = dic_features["SDLC"]
        self.editorprop_csdlc_on = dic_features["CSDLC"]
        self.editorprop_asdlc_on = dic_features["ASDLC"]
        self.editorprop_arc_on = dic_features["ARC"]
        self.editorprop_rc_on = dic_features["RC"]
        self.editorprop_gbr_on = dic_features["GBR"]
        self.editorprop_gqt_on = dic_features["GQT"]
        self.editorprop_clpcopy_on = dic_features["CLPCOPY"]
        self.editorprop_concopy_on = dic_features["CONCOPY"]

        self.last_down_time = time.time()
        self.lastsel_start = 0
        self.lastsel_end = 0

        self.i_num_editor = 2  # number of NPP views/editors window

        s_plat_arch_x86 = "32bit"
        self.GWL_WNDPROC = -4  # used to set a new address for a window procedure
        self.WM_NONE = 0x0000  # null window message
        self.WM_LBUTTONDOWN = 0x0201  # mouse left-click-down window message
        self.WM_LBUTTONDBLCLK = 0x0203  # mouse double-left-click window message
        self.WM_RBUTTONDOWN = 0x0204  # mouse right-click down window message
        self.WM_RBUTTONUP = 0x0205  # mouse right-click up window message
        self.I_VK_SHIFT = 0x10  # SHIFT virtual key code
        self.I_VK_CONTROL = 0x11  # CONTROL virtual key code
        self.I_VK_ALT = 0x12  # ALT virtual key code
        self.KSTATE_ISDOWN = 0x8000  # key pressed

        LRESULT = wintypes.LPARAM
        self.WndProcType = ctypes.WINFUNCTYPE(LRESULT, wintypes.HWND,
                                              wintypes.UINT, wintypes.WPARAM,
                                              wintypes.LPARAM)

        # window message hook functions
        self.CallWindowProc = ctypes.windll.user32.CallWindowProcW
        self.CallWindowProc.restype = LRESULT
        self.CallWindowProc.argtypes = [
            self.WndProcType, wintypes.HWND, wintypes.UINT, wintypes.WPARAM,
            wintypes.LPARAM
        ]

        b_x86 = (platform.architecture()[0].lower() == s_plat_arch_x86.lower())
        if b_x86:
            self.SetWindowLong = ctypes.windll.user32.SetWindowLongW
        else:
            self.SetWindowLong = ctypes.windll.user32.SetWindowLongPtrW
        self.SetWindowLong.restype = self.WndProcType
        self.SetWindowLong.argtypes = [
            wintypes.HWND, wintypes.INT, self.WndProcType
        ]
        # end of window message hook functions

        self.GetDoubleClickTime = ctypes.windll.user32.GetDoubleClickTime
        self.GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState
        self.SetLastError = ctypes.windll.kernel32.SetLastError
        self.GetLastError = ctypes.windll.kernel32.GetLastError

    # function to register the hook on Scintilla editors window
    def RegHook(self):
        # our own WndProc function that receives hooked windows messages
        def HOOK_MyWndProc(hwnd, msg, wparam, lparam):
            # window messages may be processed slower than actual double-left-click
            f_s_dblclick_processing_bonus = float(0.1)

            oldwndproc = None
            for i in range(0, len(self.lst_scint_hwnd)):
                # target hwnd found at index i in lst_scint_hwnd
                if self.lst_scint_hwnd[i] == hwnd:
                    # corresponding oldwndproc is picked in lst_scint_oldwndproc
                    oldwndproc = self.lst_scint_oldwndproc[i]
                    break
            if oldwndproc is None:  # FATAL ERROR ! you are doomed...
                print "\t" + self.hook_name + " Fatal error ! Hooked WndProc NOT found !"
                notepad.messageBox(self.hook_name + " Fatal error ! Hooked WndProc NOT found !", \
                 self.script_name, MESSAGEBOXFLAGS.ICONSTOP)
                return 0

            if (msg != self.WM_LBUTTONDOWN and msg != self.WM_LBUTTONDBLCLK and \
             msg != self.WM_RBUTTONDOWN and msg != self.WM_RBUTTONUP):     # if NOT in mouse hooked messages : abort
                return self.CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT : pass other msg, otherwise will block NPP
            if console.editor.getProperty(self.editorprop_hook_on) != str(
                    self.feature_on):  # if hook de-activated : abort
                return self.CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT : pass other msg, otherwise will block NPP

            if hwnd == self.lst_scint_hwnd[0]:
                curedit = editor1
            else:
                curedit = editor2

            if msg == self.WM_LBUTTONDOWN:
                f_s_dblclick = (float(self.GetDoubleClickTime()) /
                                float(1000)) + f_s_dblclick_processing_bonus
                cur_time = self.time.time()
                # save current selection before the first left-click down of a double-left-click loose this selection
                if ((cur_time - self.last_down_time) > f_s_dblclick):
                    self.lastsel_start = curedit.getSelectionStart()
                    self.lastsel_end = curedit.getSelectionEnd()
                # if second left-click down is out of the last selection, collapse this last selection to caret position
                elif (curedit.getCurrentPos() < self.lastsel_start
                      or curedit.getCurrentPos() > self.lastsel_end):
                    self.lastsel_start = curedit.getCurrentPos()
                    self.lastsel_end = curedit.getCurrentPos()
                self.last_down_time = cur_time
                return self.CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT : pass other msg, otherwise will block NPP

            b_shift_down = ((self.GetAsyncKeyState(self.I_VK_SHIFT)
                             & self.KSTATE_ISDOWN) == self.KSTATE_ISDOWN)
            b_ctrl_down = ((self.GetAsyncKeyState(self.I_VK_CONTROL)
                            & self.KSTATE_ISDOWN) == self.KSTATE_ISDOWN)
            b_alt_down = ((self.GetAsyncKeyState(self.I_VK_ALT)
                           & self.KSTATE_ISDOWN) == self.KSTATE_ISDOWN)

            b_clp_copy = (console.editor.getProperty(
                self.editorprop_clpcopy_on) == str(self.feature_on))
            b_con_copy = (console.editor.getProperty(
                self.editorprop_concopy_on) == str(self.feature_on))
            # select from clicked point the whole variable name
            if (msg == self.WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_sdlc_on) == str(self.feature_on))):
                self.o_extend_sel_from_caret.ExtendSel_AlphaNumUnderscoreDot( \
                 curedit, self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point the whole bracket [content]
            elif (msg == self.WM_LBUTTONDBLCLK and b_shift_down and b_ctrl_down and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_csdlc_on) == str(self.feature_on))):
                b_get_brackets = (console.editor.getProperty(
                    self.editorprop_gbr_on) == str(self.feature_on))
                self.o_extend_sel_from_caret.ExtendSel_To_Brackets( \
                 curedit, b_get_brackets, self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point the whole quote [content]
            elif (msg == self.WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and b_alt_down and \
              (console.editor.getProperty(self.editorprop_asdlc_on) == str(self.feature_on))):
                b_get_quotes = (console.editor.getProperty(
                    self.editorprop_gqt_on) == str(self.feature_on))
                self.o_extend_sel_from_caret.ExtendSel_To_Quotes( \
                 curedit, b_get_quotes, self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point until space/space-like chars
            elif (msg == self.WM_RBUTTONUP and not(b_shift_down) and not(b_ctrl_down) and b_alt_down and \
              (console.editor.getProperty(self.editorprop_arc_on)  == str(self.feature_on))):
                self.o_extend_sel_from_caret.ExtendSel_To_SpacesSpacesLike( \
                 curedit, curedit.getSelectionStart(), curedit.getSelectionEnd(), b_clp_copy, b_con_copy)
            # do nothing, keep the selection
            elif (msg == self.WM_RBUTTONDOWN and not(b_shift_down) and not(b_ctrl_down) and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_rc_on)  == str(self.feature_on))):
                pass
            else:
                return self.CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT : pass other msg, otherwise will block NPP

            #s_debug = "DEBUG : " + s_hook_name + " got Msg = " + hex(msg) + ", to Hwnd = " + hex(hwnd)
            #s_debug = s_debug + ", oldWndProc = " + str(oldwndproc)
            #s_debug = s_debug + " (Edit1_Hwnd = " + hex(self.lst_scint_hwnd[0]) + ", Edit2_Hwnd = " + hex(self.lst_scint_hwnd[1]) + ")"
            #s_debug = s_debug + " At " + str(self.time.time())
            #print s_debug

            return self.CallWindowProc(oldwndproc, hwnd, self.WM_NONE, 0,
                                       0)  # NULLIFY the mouse hooked messages

        # end of hook

        if self.HookDone:
            return False

        self.lst_scint_hwnd = []
        self.lst_scint_oldwndproc = []

        npp_win_hwnd, self.lst_scint_hwnd, s_npp_class, s_scint_class = self.o_get_nppscintilla_wins.GetWinsInfos(
            self.i_num_editor)

        if npp_win_hwnd is None:
            print "\t" + s_npp_class + " main window NOT found ! NO hook !"
            return False
        if len(self.lst_scint_hwnd) != self.i_num_editor:
            print "\t" + s_scint_class + " " + self.i_num_editor + " editors window NOT found ! NO hook !"
            return False
        print "\t" + "Found " + str(len(
            self.lst_scint_hwnd)) + " " + s_scint_class + " editors window"

        # get the address of our own WndProc
        self.newWndProc = self.WndProcType(HOOK_MyWndProc)

        # register the hook for each window present in lst_scint_hwnd, number must be i_num_editor
        s_hookreport = ""
        i_index = 0
        while i_index < len(self.lst_scint_hwnd):
            win_hwnd = self.lst_scint_hwnd[i_index]
            # register hooks and store oldwndproc addresses in lst_scint_oldwndproc
            self.SetLastError(0)
            oldwndproc = self.SetWindowLong(win_hwnd, self.GWL_WNDPROC,
                                            self.newWndProc)
            i_apierr = self.GetLastError()
            if i_apierr == 0:
                self.lst_scint_oldwndproc.append(oldwndproc)
                #s_hookreport = s_hookreport + "\t\t" + "DEBUG : " + hex(win_hwnd) + " / " + str(oldwndproc) + " WindowProc OK" + "\n"
                i_index = i_index + 1
            else:
                del self.lst_scint_hwnd[i_index]
                s_hookreport = s_hookreport + "\t\t" + hex(
                    win_hwnd) + " / " + "NO WindowProc ! NOT hooked !" + "\n"
        if not (s_hookreport == ""):
            s_hookreport = s_hookreport[:-1]
            print s_hookreport
        if len(self.lst_scint_hwnd) != self.i_num_editor:
            for i in range(0, len(self.lst_scint_hwnd)):
                # un-register hooks that were successfull since the whole hook is canceled
                self.SetWindowLong(self.lst_scint_hwnd[i], self.GWL_WNDPROC,
                                   self.lst_scint_oldwndproc[i])
            print "\t" + s_scint_class + " " + str(
                self.i_num_editor
            ) + " editors WindowProc NOT found ! NO hook !"
            return False

        self.HookDone = True
        return True
Example #2
0
    def __init__(self, s_script_name, s_hook_name, i_feature_on,
                 s_editorprop_hook_on, dic_features):
        import platform
        import ctypes
        from ctypes import wintypes
        import time
        self.time = time

        from Perso__Lib_Window import C_Get_NPPScintilla_Wins
        from Perso__Lib_Edit import C_Extend_Sel_From_Caret
        self.o_get_nppscintilla_wins = C_Get_NPPScintilla_Wins()
        self.o_extend_sel_from_caret = C_Extend_Sel_From_Caret()

        self.HookDone = False
        self.script_name = s_script_name
        self.hook_name = s_hook_name
        self.feature_on = i_feature_on
        self.editorprop_hook_on = s_editorprop_hook_on
        self.editorprop_sdlc_on = dic_features["SDLC"]
        self.editorprop_csdlc_on = dic_features["CSDLC"]
        self.editorprop_asdlc_on = dic_features["ASDLC"]
        self.editorprop_arc_on = dic_features["ARC"]
        self.editorprop_rc_on = dic_features["RC"]
        self.editorprop_gbr_on = dic_features["GBR"]
        self.editorprop_gqt_on = dic_features["GQT"]
        self.editorprop_clpcopy_on = dic_features["CLPCOPY"]
        self.editorprop_concopy_on = dic_features["CONCOPY"]

        self.last_down_time = time.time()
        self.lastsel_start = 0
        self.lastsel_end = 0

        self.i_num_editor = 2  # number of NPP views/editors window

        s_plat_arch_x86 = "32bit"
        self.GWL_WNDPROC = -4  # used to set a new address for a window procedure
        self.WM_NONE = 0x0000  # null window message
        self.WM_LBUTTONDOWN = 0x0201  # mouse left-click-down window message
        self.WM_LBUTTONDBLCLK = 0x0203  # mouse double-left-click window message
        self.WM_RBUTTONDOWN = 0x0204  # mouse right-click down window message
        self.WM_RBUTTONUP = 0x0205  # mouse right-click up window message
        self.I_VK_SHIFT = 0x10  # SHIFT virtual key code
        self.I_VK_CONTROL = 0x11  # CONTROL virtual key code
        self.I_VK_ALT = 0x12  # ALT virtual key code
        self.KSTATE_ISDOWN = 0x8000  # key pressed

        LRESULT = wintypes.LPARAM
        self.WndProcType = ctypes.WINFUNCTYPE(LRESULT, wintypes.HWND,
                                              wintypes.UINT, wintypes.WPARAM,
                                              wintypes.LPARAM)

        # window message hook functions
        self.CallWindowProc = ctypes.windll.user32.CallWindowProcW
        self.CallWindowProc.restype = LRESULT
        self.CallWindowProc.argtypes = [
            self.WndProcType, wintypes.HWND, wintypes.UINT, wintypes.WPARAM,
            wintypes.LPARAM
        ]

        b_x86 = (platform.architecture()[0].lower() == s_plat_arch_x86.lower())
        if b_x86:
            self.SetWindowLong = ctypes.windll.user32.SetWindowLongW
        else:
            self.SetWindowLong = ctypes.windll.user32.SetWindowLongPtrW
        self.SetWindowLong.restype = self.WndProcType
        self.SetWindowLong.argtypes = [
            wintypes.HWND, wintypes.INT, self.WndProcType
        ]
        # end of window message hook functions

        self.GetDoubleClickTime = ctypes.windll.user32.GetDoubleClickTime
        self.GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState
        self.SetLastError = ctypes.windll.kernel32.SetLastError
        self.GetLastError = ctypes.windll.kernel32.GetLastError
Example #3
0
    def RegHook(self):
        # our own WndProc function that receives hooked windows messages
        def HOOK_MyWndProc(hwnd, msg, wparam, lparam):
            f_s_dblclick_processing_bonus = float(0.1)

            oldwndproc = None
            for i in range(0, len(self.lst_scint_hwnd)):
                # target hwnd found at index i in lst_scint_hwnd
                if self.lst_scint_hwnd[i] == hwnd:
                    # corresponding oldwndproc is picked in lst_scint_oldwndproc
                    oldwndproc = self.lst_scint_oldwndproc[i]
                    break
            if oldwndproc is None:  # FATAL ERROR ! you are doomed...
                print "\t" + self.hook_name + " Fatal error ! Hooked WndProc NOT found !"
                notepad.messageBox(self.hook_name + " Fatal error ! Hooked WndProc NOT found !", \
                 self.script_name, MESSAGEBOXFLAGS.ICONEXCLAMATION)
                return 0

            if (msg != WM_LBUTTONDOWN and \
             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, otherwise will block NPP
            if console.editor.getProperty(self.editorprop_hook_on) != str(
                    self.feature_on):  # if hook de-activated : abort
                return CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT pass other msg, otherwise will block NPP

            # save selection before the first left-click down of a double-left-click loose it
            if msg == WM_LBUTTONDOWN:
                f_s_dblclick = (float(GetDoubleClickTime()) /
                                float(1000)) + f_s_dblclick_processing_bonus
                cur_time = time.time()
                if (cur_time - self.last_down_time) > f_s_dblclick:
                    self.lastsel_start = editor.getSelectionStart()
                    self.lastsel_end = editor.getSelectionEnd()
                else:
                    if (editor.getCurrentPos() < self.lastsel_start
                            or editor.getCurrentPos() > self.lastsel_end):
                        self.lastsel_start = editor.getCurrentPos()
                        self.lastsel_end = editor.getCurrentPos()
                self.last_down_time = cur_time
                return CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT pass other msg, 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)

            b_clp_copy = (console.editor.getProperty(
                self.editorprop_clpcopy_on) == str(self.feature_on))
            b_con_copy = (console.editor.getProperty(
                self.editorprop_concopy_on) == str(self.feature_on))
            # select from clicked point the whole variable name
            if (msg == WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_sdlc_on) == str(self.feature_on))):
                self.o_extend_sel_from_caret.ExtendSel_AlphaNumUnderscoreDot( \
                 self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point the whole bracket [content]
            elif (msg == WM_LBUTTONDBLCLK and b_shift_down and b_ctrl_down and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_csdlc_on) == str(self.feature_on))):
                b_get_brackets = (console.editor.getProperty(
                    self.editorprop_gbr_on) == str(self.feature_on))
                self.o_extend_sel_from_caret.ExtendSel_To_Brackets( \
                 b_get_brackets, self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point the whole quote [content]
            elif (msg == WM_LBUTTONDBLCLK and b_shift_down and not(b_ctrl_down) and b_alt_down and \
              (console.editor.getProperty(self.editorprop_asdlc_on) == str(self.feature_on))):
                b_get_quotes = (console.editor.getProperty(
                    self.editorprop_gqt_on) == str(self.feature_on))
                self.o_extend_sel_from_caret.ExtendSel_To_Quotes( \
                 b_get_quotes, self.lastsel_start, self.lastsel_end, b_clp_copy, b_con_copy)
            # select from clicked point until space/space-like chars
            elif (msg == WM_RBUTTONUP and not(b_shift_down) and not(b_ctrl_down) and b_alt_down and \
              (console.editor.getProperty(self.editorprop_arc_on)  == str(self.feature_on))):
                self.o_extend_sel_from_caret.ExtendSel_To_SpacesSpacesLike( \
                 editor.getSelectionStart(), editor.getSelectionEnd(), b_clp_copy, b_con_copy)
            # do nothing, keep the selection
            elif (msg == WM_RBUTTONDOWN and not(b_shift_down) and not(b_ctrl_down) and not(b_alt_down) and \
              (console.editor.getProperty(self.editorprop_rc_on)  == str(self.feature_on))):
                dummy = 0
            else:
                return CallWindowProc(
                    oldwndproc, hwnd, msg, wparam, lparam
                )  # -> IMPORTANT pass other msg, otherwise will block NPP

            #s_debug = "DEBUG " + s_hook_name + " Message = " + hex(msg) + " to hwnd = " + hex(hwnd)
            #s_debug = s_debug + " Forwarded To oldwndproc = " + str(oldwndproc) + " At " + str(datetime.now())
            #print s_debug
            return CallWindowProc(oldwndproc, hwnd, WM_NONE, 0,
                                  0)  # NULLIFY the mouse hooked messages

        if self.HookDone:
            return False

        self.lst_scint_hwnd = []
        self.lst_scint_oldwndproc = []

        o_get_nppscintilla_wins = C_Get_NPPScintilla_Wins()
        npp_win_hwnd, self.lst_scint_hwnd, s_npp_class, s_scint_class = o_get_nppscintilla_wins.GetWinsInfos(
        )

        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)
        print "\t" + "Found " + str(len(
            self.lst_scint_hwnd)) + " " + s_scint_class + " Handle(s)"

        # get the address of our own WndProc
        self.newWndProc = WndProcType(HOOK_MyWndProc)

        # register the hook for each window present in lst_scint_hwnd
        s_errlist = ""
        i_index = 0
        while i_index < len(self.lst_scint_hwnd):
            win_hwnd = self.lst_scint_hwnd[i_index]
            # register hook and store oldwndproc addresses in lst_scint_oldwndproc
            SetLastError(0)
            oldwndproc = SetWindowLong(win_hwnd, GWL_WNDPROC, self.newWndProc)
            i_apierr = GetLastError()
            if i_apierr == 0:
                self.lst_scint_oldwndproc.append(oldwndproc)
                i_index = i_index + 1
            else:
                del self.lst_scint_hwnd[i_index]
                s_errlist = s_errlist + "\t\t" + hex(
                    win_hwnd) + " / " + "NO WindowProc ! NOT hooked !" + "\n"
        if not (s_errlist == ""):
            s_errlist = s_errlist[:-1]
            print s_errlist
        if len(self.lst_scint_hwnd) == 0:
            print "\t" + s_scint_class + " window(s) or WindowProc(s) NOT found or NO hook !"
            return False

        self.o_extend_sel_from_caret = C_Extend_Sel_From_Caret()

        self.HookDone = True
        return True