PythonScript Toggleable Script?
-
You typically don’t delete topics here.
WHAT exactly do you have “figured out”?
It is good to post what you have solved and how you’ve solved it, so others can benefit. -
@alan-kilborn I figured out how to have the Script remember if it was toggled on or off after execution. I did this by writing to a text file to store data indicating what toggle the script was set to. This way the script can “remember” what it was set to by opening up that text file at the beginning of each execution.
-
Well…OK.
But how does that solve the problem of how to have a mode where you don’t have to hold Shift+Alt while making a column block selection? -
@alan-kilborn I used the keyboard library which is 100% pure Python so I was able to just drop it in the PythonScript/lib folder to utilize it. From there I used the keyboard.press and keyboard.release functions to press and release Alt (turns out I just have to hold Alt to use column select not Alt and Shift).
I do have one minor concern with how my script is working though which is that if the user closes out Notepad++ without toggling my script to off, the Alt key remains to be held even when Notepad++ is closed for some reason, is there a way I can detect when the user closes Notepad++ to account for this?
-
@john-doe-1 said in PythonScript Toggleable Script?:
I used the keyboard library which is 100% pure Python so I was able to just drop it in the PythonScript/lib folder to utilize it. From there I used the keyboard.press and keyboard.release functions to press and release Alt.
This is, IMO, a bad way to do this.
Doesn’t this cut off the Alt key from functionally being part of any shortcuts that use it?
And doesn’t it neuter its functionality in dialog boxes (e.g. Find) where Alt can be used in combination with other keys to activate controls, e.g., Alt+c toggles the current setting for the Match case checkbox.
And lastly, Alt+f will activate the File menu, etc.
Sure…I suppose if you never use these things…(turns out I just have to hold Alt to use column select not Alt and Shift)
I don’t know what this means.
Alt alone only works to column-select when used with the mouse, not the keyboard.is there a way I can detect when the user closes Notepad++
A shutdown notification can be configured via NOTIFICATION.SHUTDOWN.
-
@alan-kilborn said in PythonScript Toggleable Script?:
Doesn’t this cut off the Alt key from functionally being part of any shortcuts that use it?
And doesn’t it neuter its functionality in dialog boxes (e.g. Find) where Alt can be used in combination with other keys to activate controls, e.g., Alt+c toggles the current setting for the Match case checkbox.
And lastly, Alt+f will activate the File menu, etc.Actually, I think my brain was totally out to lunch with this reply.
I think it plays to the fact that I have no idea what the OP is trying to accomplish here.
I suppose it works logically if you enter this “special mode”, then all you do is make arrow and shift+arrow movements, but if you want to insert a character somewhere, would it be registered as Alt+t if you press t, with the OP’s method.
But, I really don’t know, at all. :-( -
@alan-kilborn Edit
-
@alan-kilborn @alan-kilborn Sorry input was being weird had to edit this reply. You make some good points, yes the holding of the “Alt” key does present some issues, most of them minor and not a problem for my uses. Except for inserting the “t” character and it being registed as “Alt” + “t” which would switch windows (depending on your configurations), that is a bit more of an issue. Do you have any ideas of an alternate way to achieve this? Thanks for your help so far!
-
If your goal is to have the “alt” key behave as “sticky”, Windows OS has an accessibility feature (“ease of access - keyboard”) for that.
https://www.google.com/search?q=windows+10+sticky+alt+key =>
https://winaero.com/turn-on-or-off-sticky-keys-in-windows-10/ or https://www.howtogeek.com/739764/how-to-turn-off-sticky-keys-on-windows-10/ or …No need to highjack the Alt key or any such thing.
-
@peterjones Thanks but I wanted to make it a toolbar icon attached to a PythonScript, I realize the same function can be achieved with Keyboard Shortcuts and Sticky Keys but having a toolbar icon is just my personal preference.
-
@john-doe-1 said in PythonScript Toggleable Script?:
Do you have any ideas of an alternate way to achieve this?
Yes, here’s a demo script I call
RectangularSelectModeToggle.py
. Each time it is run (hint: you can tie the running of it to a toolbar button) it toggles the shift+arrows selection functionality between selecting normal (what’s called a stream selection) and a selecting a column block (called rectangular selection). The “Alt” key is not involved. The script is fairly “low level”, and not a short one.# -*- coding: utf-8 -*- from __future__ import print_function from Npp import * import inspect import os import ctypes from ctypes import wintypes import platform #------------------------------------------------------------------------------- user32 = ctypes.WinDLL('user32') notepad.hwnd = user32.FindWindowW(u'Notepad++', None) editor1.hwnd = user32.FindWindowExW(notepad.hwnd, None, u'Scintilla', None) editor2.hwnd = user32.FindWindowExW(notepad.hwnd, editor1.hwnd, u'Scintilla', None) LRESULT = wintypes.LPARAM WndProcType = ctypes.WINFUNCTYPE( LRESULT, # return type wintypes.HWND, wintypes.UINT, wintypes.WPARAM, wintypes.LPARAM # arguments ) running_32bit = platform.architecture()[0] == '32bit' SetWindowLong = user32.SetWindowLongW if running_32bit else user32.SetWindowLongPtrW SetWindowLong.restype = WndProcType SetWindowLong.argtypes = [wintypes.HWND, wintypes.INT, WndProcType] GWL_WNDPROC = -4 WM_KEYDOWN = 0x100 WM_KEYUP = 0x101 WM_SYSKEYDOWN = 0x104 WM_SYSKEYUP = 0x105 WM_KILLFOCUS = 0x8 VK_SHIFT = 0x10 VK_CONTROL = 0x11 VK_MENU = VK_ALT = 0x12 VK_LEFT = 0x25 VK_UP = 0x26 VK_RIGHT = 0x27 VK_DOWN = 0x28 #------------------------------------------------------------------------------- class RSMT(object): def __init__(self): self.debug = True if 1 else False self.this_script_name = inspect.getframeinfo(inspect.currentframe()).filename.split(os.sep)[-1].rsplit('.', 1)[0] self.shift_pressed = self.ctrl_pressed = self.alt_pressed = False self.altless_rectangular_select_mode_active = False # if this mode is active, user doesn't have to hold Alt while pressing Shift+arrows in order to make a rectangular selection self.new_editor1_wnd_proc_hook_for_SetWindowLong = WndProcType(self.new_editor1_wnd_proc_hook) self.orig_editor1_wnd_proc = SetWindowLong(editor1.hwnd, GWL_WNDPROC, self.new_editor1_wnd_proc_hook_for_SetWindowLong) self.new_editor2_wnd_proc_hook_for_SetWindowLong = WndProcType(self.new_editor2_wnd_proc_hook) self.orig_editor2_wnd_proc = SetWindowLong(editor2.hwnd, GWL_WNDPROC, self.new_editor2_wnd_proc_hook_for_SetWindowLong) def common_editor_wnd_proc_hook(self, hwnd, msg, wParam, lParam): retval = True # default to allowing something other than this code to handle this message if msg in [WM_KEYDOWN, WM_SYSKEYDOWN]: if wParam == VK_SHIFT: self.shift_pressed = True elif wParam == VK_CONTROL: self.ctrl_pressed = True elif wParam == VK_ALT: self.alt_pressed = True elif wParam in [ VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN ]: modifiers = '' modifiers += 'SHIFT+' if self.shift_pressed else '' modifiers += 'CTRL+' if self.ctrl_pressed else '' modifiers += 'ALT+' if self.alt_pressed else '' key = '' key += 'LEFT' if wParam == VK_LEFT else '' key += 'UP' if wParam == VK_UP else '' key += 'RIGHT' if wParam == VK_RIGHT else '' key += 'DOWN' if wParam == VK_DOWN else '' self.print(modifiers + key) if self.altless_rectangular_select_mode_active: if self.shift_pressed and not self.ctrl_pressed and not self.alt_pressed: retval = False # allow no further processing of this message; it will be handled here if wParam == VK_LEFT: editor.charLeftRectExtend() elif wParam == VK_UP: editor.lineUpRectExtend() elif wParam == VK_RIGHT: editor.charRightRectExtend() elif wParam == VK_DOWN: editor.lineDownRectExtend() elif msg in [WM_KEYUP, WM_SYSKEYUP]: if wParam == VK_SHIFT: self.shift_pressed = False elif wParam == VK_CONTROL: self.ctrl_pressed = False elif wParam == VK_ALT: self.alt_pressed = False elif msg == WM_KILLFOCUS: self.shift_pressed = self.ctrl_pressed = self.alt_pressed = False return retval def new_editor1_wnd_proc_hook(self, hwnd, msg, wParam, lParam): retval = self.common_editor_wnd_proc_hook(hwnd, msg, wParam, lParam) if retval: retval = self.orig_editor1_wnd_proc(hwnd, msg, wParam, lParam) return retval def new_editor2_wnd_proc_hook(self, hwnd, msg, wParam, lParam): retval = self.common_editor_wnd_proc_hook(hwnd, msg, wParam, lParam) if retval: retval = self.orig_editor2_wnd_proc(hwnd, msg, wParam, lParam) return retval def toggle(self): editor.setEmptySelection(editor.getCurrentPos()) self.altless_rectangular_select_mode_active = not self.altless_rectangular_select_mode_active self.mb('Alt-less column select mode is now {}'.format('active' if self.altless_rectangular_select_mode_active else 'inactive')) def print(self, *args): if self.debug: #console.show() print('RSMT:', *args) def mb(self, msg, flags=0, title=''): # a message-box function return notepad.messageBox(msg, title if title else self.this_script_name, flags) #------------------------------------------------------------------------------- if __name__ == '__main__': try: rsmt except NameError: rsmt = RSMT() rsmt.toggle()
-
-
@alan-kilborn Thanks for that! I still would like to know how to check if Notepad++ is closed or tabbed out of for future projects. Is there a function from Notepad, Editor or somewhere that can return whether or not Notepad++ is the active window? I would like to remedy this issue in my Script for satisfaction’s sake.
-
@john-doe-1 said in PythonScript Toggleable Script?:
check if Notepad++ is closed
You scan do this with
NOTIFICATION.SHUTDOWN
in anotepad.callback
. To see how this works if you don’t know, type notepad.callback into the editor and then invoke PythonScript’s context-sensitive help on it.There’s also
SCINTILLANOTIFICATION.FOCUSOUT
which you could experiment with to see if it meets your needs. That one is aneditor.callback
.can return whether or not Notepad++ is the active window?
I suppose you could try things with the windows API function GetForegroundWindow.
-
Your paradigm is BAD and causing you problems.
Try this script out for size:
# encoding=utf-8 """in response to https://community.notepad-plus-plus.org/topic/22890/ and 22919 alternate paradigm """ from Npp import notepad, editor, SELECTIONMODE, STATUSBARSECTION try: columnSelectMode startPos endPos except NameError: #console.show() console.write('initialize toggle mode for the first time\n') columnSelectMode = False startPos = None endPos = None if not columnSelectMode: startPos = editor.getCurrentPos() endPos = startPos notepad.setStatusBar(STATUSBARSECTION.DOCTYPE, "In Rectangle/Column Selection Mode") else: endPos = editor.getCurrentPos() editor.setSel(startPos, endPos) editor.setSelectionMode( SELECTIONMODE.RECTANGLE ) # this overrides the statusbar.. but the refresh UI will overwrite that with default notepad.setStatusBar(STATUSBARSECTION.DOCTYPE, "") # use the upcoming activateFile to refresh UI # otherwise, it doesn't _look_ like column/rectangle select) notepad.activateFile(notepad.getCurrentFilename()) columnSelectMode = not columnSelectMode #console.show() #console.write("toggle selection mode to {}: {} .. {}\n".format(columnSelectMode, startPos, endPos))
-
-
@peterjones the statement:
editor.setSelectionMode( SELECTIONMODE.RECTANGLE )
doesn’t seem to work, I tested it in a simple script with nothing else going on and this makes no changes to the selection mode, I’ve no idea why.
-
That’s what I thought at first. But when I triggered the refresh (the activate file line), it updated and showed that it really did change what was shown to be the rectangle – that’s why I included that line in the script, and included comments to say it was needed to get it to show it’s a rectangle.
You can also tell that it was rectangle by just doing the editor.getSelectionMode() which returns a 1 (IIRC) for rectangle, or just do the copy then paste in the new location, and see it only grabbed the rectangle, not the full lines. Actually, I first saw it was working when I swapped to another tab and then back, and saw it was suddenly a rectangle instead of the stream it looked like.
-
@peterjones Thank you, I saw your reply to my other post also. My apologies, I’ll delete it and refrain from that in the future.
-
@peterjones said in PythonScript Toggleable Script?:
editor.getSelectionMode() which returns a 1 (IIRC) for rectangle
That is indeed correct, and this is also available returning True/False:
editor.selectionIsRectangle()
-
Since it apparently confused others, I will be more explicit about the example I gave above: it has a slightly different usage model than your explain seems to imply. If we read your usage model correctly, you want to have this script toggle the “column” mode, and you are then using shift+arrows to make the block selection live.
In my script, I figured: if you don’t want to faff around with ALT, then also don’t faff around with SHIFT. My usage model (for the script shown above) is “run script to start the column/rectangle selection; move cursor (either normal arrow or just click, since you’re already clicking the script on the toolbar); run script to end column/rectangle selection and then refresh the display so it looks like a column selection”.
But if you or your users insist on holding down the SHIFT, my script (above) will also work for that – it will look like a normal selection until the end when you run the script the second time, then it will convert the selection from normal to rectangular.
Which means, really, the script could be simplified to just run
from Npp import editor, notepad, SELECTIONMODE editor.setSelectionMode(SELECTIONMODE.RECTANGLE) notepad.activateFile(notepad.getCurrentFilename())
Then the usage model would be “1) move your cursor to the start of where you want to select (via mouse or keyboard); 2) SHIFT+arrow or SHIFT+click to draw a normal selection; 3) run the script to convert the normal selection to a rectangle/column selection”. Fewer clicks. Call the script “convert active selection to rectangle” and be done with it.
-
So here are some example screenshot-videos of using the two
I assigned the ⇅ button to the “toggle” (the post that has the script with
"alternate paradigm"
in the comments).For the ⇅ , I record the sequence
- start selection with a click
- click the ⇅ button to start the rectangle/column selection
- end selection with a click
- click the ⇅ button to end the rectangle/column selection, and convert it to visually be a rectangle selection
- start new selection with a click
- click the ⇅ button to start the rectangle/column selection
- extend new selection with SHIFT+arrow
- click the ⇅ button to end the rectangle/column selection, and convert it to visually be a rectangle selection
You will see that the status bar reflects the correct state of when you have clicked ⇅ the first time (so the script is in “active” mode), and that it clears itself when you do the second ⇅ (so it’s converted)
---------------------
I assigned the other button to the “simplest” – the three-line version shown in my later post.
For the , I recorded the sequence
- start the selection with a click
- extend the selection with SHIFT+ARROW
- convert the selection to rectangular by calling the 🛈 script
This doesn’t show the status, because the button is a one-time thing, not a “in the active mode” thing.
Either should work. Both avoid any low-level programming or callbacks – they just use standard, simple PythonScript calls.
The second has the benefit of being really simple, and doesn’t even need to save state. If you or your user want to convert a normal selection to rectangle, just click the button after making the selection. Don’t need to worry about the status bar. Easiest to use. Easiest to maintain. You can always decide to use that to change any stream selection into a rectangle, whether you were thinking “I need to select a rectangle” or not. Fewer clicks.