且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

我可以在Windows文本编辑上下文菜单中添加自定义粘贴选项吗?

更新时间:2023-12-06 08:25:46

问题询问如何编辑Edit控件的上下文菜单,
有点不清楚这是否是要重命名或编辑文件时,下面的
AutoHotkey脚本在资源管理器中使用记事本编辑文件时,会复制
的编辑控制菜单。
它添加了一个向编辑控件发送字符串的按钮。

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.

脚本显示一个自定义上下文菜单,当编辑控件正确时显示
单击,
,或者将Edit控件置于焦点并按下 AppsKey

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.

注意:下面的脚本已经在Windows 7,
上进行了测试,但是这些方法应该在Windows XP上可以使用。

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

注意:资源管理器地址栏中还使用了Edit控件,
,但是脚本会考虑到这一点。

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

注意:您请求的方法是轻量级的,
AutoHotkey可以与一个exe一起运行文件(小于2MB),
和一个脚本文件。

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://***.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://***.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
}

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