Can I add a custom paste option to the windows tex

2019-08-03 18:39发布

问题:

I am looking for a way to add an option(s) to the right click context menu when editing text on a WinXP machine. I already do a lot of copy/pasting on it, so the clipboard is always changing, but there is one string I type repeatedly in almost every file I edit.

I've already added some custom option to the context menu for .zip files to batch unzip them, but I'm not having any luck finding a way to add this.

The machine is used for a single purpose and I try to keep it as stable as possible so I'm trying to stay away from any new third-party software that could bloat the system.

回答1:

I don't think there's an extension point for that sort of thing. You'd have to inject code into every process that has a window with a text box control, which would be complicated and frowned upon by most anti-virus applications.

I know you said you wanted to avoid third-party software, but there really isn't any way around it. A program like AutoIt will allow you to create a custom keyboard shortcut to paste whatever text you like into almost any application. It would probably be much more stable than any custom program written in the short term.

You can even compile the automation script to a standalone executable if you don't want to install the entire AutoIt distribution on the machine.



回答2:

Assuming you are referring to the Edit control context menu. You can achieve this by cloning and amending the Edit control context menu, via AutoHotkey. If the context menu is a for a different type of control, the same principle applies but it may be harder to recreate the existing menu item functions.

To 'add' a menu item, the simplest method would be to replace the entire menu with your own custom context menu. With your custom menu item at the top of it, and you would probably want to recreate the Undo/Cut/Copy/Paste/Delete/Select All items that appear on the Edit control. Using ControlGet, vText, Selected to recreate the Copy function for example. You use #IfWinActive to make the menus only appear if a certain window is the active window, e.g. only if Notepad is the active window. You would also need to capture right-clicks via the RButton hotkey and/or capture AppsKey presses, and use ControlGetFocus to check if an Edit control was in focus, and MouseGetPos to check if an Edit control was under the cursor. So there would be a bit of work involved. Regarding capturing right-clicks, see the link below, where you would replace LButton with RButton. Good luck!

Is it possible to catch the close button and minimize the window instead? AutoHotKey

Similar question: Can I edit the context menu of a text field (not Explorer context menu)?

Note:
- For typing long/repetitive strings, the use of hotstrings in AutoHotkey can really facilitate this. Achievable in literally one line of code.
- For batch jobs involving zip files perhaps try 7-Zip and using command lines parameters in AutoHotkey. This could probably be achieved in around 10 or 20 lines of code.

AutoHotkey is very lightweight, about 1MB, you could try it for a day or two, possibly watch a short 'hello world' tutorial video, it can be quite easy to get started.



回答3:

The question asks how to edit the context menu for an Edit control, it it slightly unclear whether this is wanted for renaming or editing files, the AutoHotkey script below replicates the Edit control menu when editing files in Explorer and using Notepad. It adds a button that sends a string to the Edit control.

The script shows a custom context menu, when an Edit control is right-clicked, or when an Edit control is focused and the AppsKey is pressed.

Note: The script below is tested on Windows 7, but the methods should work on Windows XP.

Note: The Explorer address bar also uses an Edit control, however, this is taken into account by the script.

Note: You requested a method that is lightweight, AutoHotkey can be run with one exe file (under 2MB in size), and one script file. Scripts can also be compiled to small exes.

;AutoHotkey script for:
;contextmenu - Can I add a custom paste option to the windows text editing context menu? - Stack Overflow
;http://stackoverflow.com/questions/17370415/can-i-add-a-custom-paste-option-to-the-windows-text-editing-context-menu/41343891#41343891

;see also:
;windows - Can I edit the context menu of a text field (not Explorer context menu)? - Stack Overflow
;http://stackoverflow.com/questions/39827324/can-i-edit-the-context-menu-of-a-text-field-not-explorer-context-menu/41343741#41343741

;tested on Windows 7

GroupAdd, WinGroupFolder, ahk_class CabinetWClass ;explorer
#IfWinActive, ahk_group WinGroupFolder
$RButton Up:: ;explorer - custom Edit control menu
$AppsKey:: ;explorer - custom Edit control menu
#IfWinActive, ahk_class Notepad
$RButton Up:: ;notepad - custom Edit control menu
$AppsKey:: ;notepad - custom Edit control menu

;STAGE - create menu if not already created
if !vIsReady
{
    Menu, EditMenu, Add, &My Item, MyItem
    Menu, EditMenu, Add ;------------------------------
    Menu, EditMenu, Add, &Undo, EditUndo
    Menu, EditMenu, Add ;------------------------------
    Menu, EditMenu, Add, Cu&t, EditCut
    Menu, EditMenu, Add, &Copy, EditCopy
    Menu, EditMenu, Add, &Paste, EditPaste
    Menu, EditMenu, Add, &Delete, EditDelete
    Menu, EditMenu, Add ;------------------------------
    Menu, EditMenu, Add, Select &All, EditSelectAll

    VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
    VarSetCapacity(vPos1X, 4), VarSetCapacity(vPos2X, 4)
    vIsReady := 1
}

;STAGE - perform certain checks, if any of them fail
;then let hotkeys perform their normal function,
;start by stating that, so far, the checks have not failed
vRet := 1

;check - if active control is an Edit/RichEdit control
if vRet
{
    WinGet, hWnd, ID, A
    ControlGetFocus, vCtlClassNN, ahk_id %hWnd%
    ControlGet, hCtl, Hwnd, , %vCtlClassNN%, ahk_id %hWnd%
    WinGetClass, vWinClass, ahk_id %hCtl%
    if !(SubStr(vWinClass, 1, 4) = "Edit") && !(SubStr(vWinClass, 1, 8) = RichEdit)
    vRet := 0
}

;check - if a right-click was performed, the control
;under the cursor must be the active control
if vRet && InStr(A_ThisHotkey, "RButton")
{
    CoordMode, Mouse, Screen
    MouseGetPos, vPosX, vPosY, , hCtl2, 3
    if !(hCtl2 = hCtl)
    vRet := 0
}

;check - the Edit control must be for a file icon and not the address bar
if vRet
{
    ;hWndParent := DllCall("user32\GetParent", Ptr,hCtl, Ptr)
    hWndParent := DllCall("user32\GetAncestor", Ptr,hCtl, UInt,1, Ptr) ;GA_PARENT := 1
    WinGetClass, vWinClassParent, ahk_id %hWndParent%
    if (vWinClassParent = "ComboBox")
    vRet := 0
}

;if a check has failed, then let hotkeys perform their normal function
if !vRet
{
    if InStr(A_ThisHotkey, "RButton")
        SendInput {Click right}
    if InStr(A_ThisHotkey, "AppsKey")
        SendInput {AppsKey}
    Return
}

;STAGE - if clicked Edit control, menu will appear
;relative to cursor coordinates retrieved earlier,
;if pressed AppsKey, menu will appear in centre of Edit control
if !InStr(A_ThisHotkey, "RButton")
{
    WinGetPos, vPosX, vPosY, vPosW, vPosH, ahk_id %hCtl%
    vPosX += vPosW/2, vPosY += vPosH/2
}

;STAGE - retrieve information from Edit control
;and disable menu items accordingly
;Undo - check undo status (is undo available)
;Cut - check text selection > 0
;Copy - check text selection > 0
;Paste - check clipboard not empty
;Delete - check text selection > 0
;Select All - always available

SendMessage, 0xC6, 0, 0, , ahk_id %hCtl% ;EM_CANUNDO := 0xC6
vOptU := ErrorLevel ? "En" : "Dis" ;1=undo available/0=undo not available
ControlGet, vText, Selected, , , ahk_id %hCtl%
vOptT := StrLen(vText) ? "En" : "Dis"
vOptC := StrLen(Clipboard) ? "En" : "Dis"

Menu, EditMenu, % vOptU "able", &Undo, EditUndo
Menu, EditMenu, % vOptT "able", Cu&t, EditCut
Menu, EditMenu, % vOptT "able", &Copy, EditCopy
Menu, EditMenu, % vOptC "able", &Paste, EditPaste
Menu, EditMenu, % vOptT "able", &Delete, EditDelete

;STAGE - get Edit control character positions
;(unfortunately showing the custom menu ends the rename mode,
;we get the Edit control character positions in order to restore them later)
SendMessage, 0xB0, &vPos1, &vPos2, , ahk_id %hCtl% ;EM_GETSEL := 0xB0
vPos1 := NumGet(vPos1), vPos2 := NumGet(vPos2)

;STAGE - show menu
CoordMode, Menu, Screen
Menu, EditMenu, Show, %vPosX%, %vPosY%
Return

;==============================

;STAGE - replicate standard Edit control menu items
;(or perform custom menu function)
;(unfortunately showing the custom menu ends the rename mode,
;so the Edit control has to be put into rename again,
;and the character positions restored)
EditUndo:
EditCut:
EditCopy:
EditPaste:
EditDelete:
EditSelectAll:
MyItem:

;STAGE - enter rename mode again
IfWinActive, ahk_group WinGroupFolder
{
    SendInput {F2}
    Loop, 20
    {
        ControlGetFocus, vCtlClassNN, ahk_id %hWnd%
        if (SubStr(vCtlClassNN, 1, 4) = "Edit")
            break
        Sleep 50
    }
    if !(SubStr(vCtlClassNN, 1, 4) = "Edit")
    {
        MsgBox % "error"
        Return
    }
    ControlGet, hCtl, Hwnd, , % vCtlClassNN, ahk_id %hWnd%

    ;STAGE - restore character positions
    if !InStr(A_ThisLabel, "SelectAll")
    {
        vRet := 0
        Loop, 100
        {
            SendMessage, 0xB1, vPos1, vPos2, , ahk_id %hCtl% ;EM_SETSEL := 0xB1
            SendMessage, 0xB0, &vPos1X, &vPos2X, , ahk_id %hCtl% ;EM_GETSEL := 0xB0
            vPos1X := NumGet(vPos1X), vPos2X := NumGet(vPos2X)
            if (vPos1 = vPos1X) && (vPos2 = vPos2X)
            {
                vRet := 1
                break
            }
            Sleep 50
            if !vRet
            {
                MsgBox % "error"
                Return
            }
        }
    }
}

;STAGE - perform standard Edit control menu functions
if InStr(A_ThisLabel , "Undo")
    SendMessage, 0x304, , , , ahk_id %hCtl% ;WM_UNDO := 0x304
if InStr(A_ThisLabel , "Cut")
    SendMessage, 0x300, , , , ahk_id %hCtl% ;WM_CUT := 0x300
if InStr(A_ThisLabel , "Copy")
    SendMessage, 0x301, , , , ahk_id %hCtl% ;WM_COPY := 0x301
if InStr(A_ThisLabel , "Paste")
    SendMessage, 0x302, , , , ahk_id %hCtl% ;WM_PASTE := 0x302
if InStr(A_ThisLabel , "Delete")
    SendMessage, 0x303, , , , ahk_id %hCtl% ;WM_CLEAR := 0x303
if InStr(A_ThisLabel , "SelectAll")
    SendMessage, 0xB1, 0, -1, , ahk_id %hCtl% ;EM_SETSEL := 0xB1

;STAGE - actions to take if user chooses custom menu item
if InStr(A_ThisLabel , "MyItem")
{
    vText := "My String"
    ;ControlSend, , % vText, ahk_id %hCtl% ;use SendInput instead since capitalisation can be unreliable
    SendInput {Raw}%vText%
}

;STAGE - actions to take if user chooses custom menu item
if 0 ;this comments out the 9 lines below
if InStr(A_ThisLabel , "MyItem") && !(vText = "")
{
    MsgBox, 0x40003, , % "Choose 'Yes' to search for:`r`n" vText
    IfMsgBox Yes
    {
        vUrl := "http://www.google.co.uk/search?q=" UriEncode(vText)
        Run, "%vUrl%"
    }
}

Return
#IfWinActive

;==================================================

;URL encoding - Rosetta Code
;https://www.rosettacode.org/wiki/URL_encoding#AutoHotkey

; Modified from https://autohotkey.com/board/topic/75390-ahk-l-unicode-uri-encode-url-encode-function/?p=480216
UriEncode(Uri)
{
    VarSetCapacity(Var, StrPut(Uri, "UTF-8"), 0)
    StrPut(Uri, &Var, "UTF-8")
    f := A_FormatInteger
    SetFormat, IntegerFast, H
    While Code := NumGet(Var, A_Index - 1, "UChar")
        If (Code >= 0x30 && Code <= 0x39 ; 0-9
            || Code >= 0x41 && Code <= 0x5A ; A-Z
            || Code >= 0x61 && Code <= 0x7A) ; a-z
            Res .= Chr(Code)
        Else
            Res .= "%" . SubStr(Code + 0x100, -1)
    SetFormat, IntegerFast, %f%
    Return, Res
}

;==================================================