AutoHotkey able to capture firefox tab? - firefox

It is a bit beyond of my knowledge, so I copy&pasted the whole script.
But I was rejected with a message, which reads, (Firefox version is 28.0) Anybody please help me.
Error: Call to nonexistent function.
Specifically: Acc_Get( ... ...
SetTitleMatchMode 2
WinGet, windows, List, Mozilla Firefox
Loop %windows% {
hwnd := windows%A_Index%
;// Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")
page_tab_list := Acc_Get("object", "application.grouping2.property_page.tool_bar3.page_tab_list", "", "ahk_id" hwnd)
For Each, tab in Acc_Children(page_tab_list)
if tab.accName(0) = "https://www.apple.com/" {
tab.accDoDefaultAction(0) ;// remove line to NOT activate tab
WinActivate ahk_id %hwnd%
break 2
}
}

This script simply walks through all tabs until it finds the correct one, via the page title in the window title. Sleep timer can be adjusted.
SetTitleMatchMode 2
needle := "Stack Overflow"
WinActivate, Firefox
Loop {
WinGetTitle, title
IfWinNotActive, Firefox
break
if (InStr(title,needle))
Break
Else
send ^{PgUp}
sleep 50
}

You didn't take all the dependencies from the source. You are missing the required Acc Library.
; Acc.ahk https://github.com/sancarn/ACC.AHK/blob/master/AccV2.ahk
; ACC Tutorial: https://www.autohotkey.com/boards/viewtopic.php?f=7&t=40590

Related

How to handle optional windows in Autoit?

I am automating a software installation in Windows7 using AutoIt.
During the installation, in between if a error window appears. I want to click ENTER.
If the error window not appears then I should NOT do anything. Simply its should go to the next section.
I have tried "WinActive and WinWaitActive" But its waiting for the window to appear. If window not appears its not going to the next screen.
Any idea how to handle this situation?
Do a while loop:
$w = 0
While($w = 0)
If(WinActive("ERROR WINDOW"))Then
Send("{ENTER}")
$w = 1
ElseIf(ControlGetText("YOUR WINDOW", "", "[CLASS:Static; INSTANCE:2]") <> "SOME TEXT") Then
$w = 1
;and something else
EndIf
Sleep(1000)
WEnd
AdlibRegister() is the right choice. From the help file:
"... typically to check for unforeseen errors. For example, you could use adlib in a script which causes an error window to pop up unpredictably."
Each 100 ms (may be adjusted) the function is called to check the appearing of your error dialog:
Global $sErrorWindow = 'ErrorDialogName'
Global $iDelayHowOftenDoTheFunctionCall = 100
AdlibRegister('_isErrorWindowDisplayed', $iDelayHowOftenDoTheFunctionCall)
Func _isErrorWindowDisplayed()
If WinActive($sErrorWindow) <> 0 Then
WinActivate($sErrorWindow) ; just to be sure that the ENTER command is on the correct window/dialog
; either do
Send('{ENTER}')
; or
ControlClick('title', 'text', 'controlID')
EndIf
EndFunc
; do your software installation processing here
; ...
; ...
; don't forget to unregister the function at the end
AdlibUnRegister('_isErrorWindowDisplayed')

Navigate Shell command not working when the path includes an hash

I'm having problem using the Navigate Shell command when the path include an # sign.
; this will create 2 folders at the root of your C: drive
myPath1 := "C:\delete_me\"
myPath2 := "C:\delete#me\"
if !FileExist(myPath1)
FileCreateDir, %myPath1%
if !FileExist(myPath2)
FileCreateDir, %myPath2%
; make an Explorer active and press Alt-1 and Alt-2
return
!1::
strWinId := WinExist("A")
TrayTip, %myPath1%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath1)
return
!2::
strWinId := WinExist("A")
TrayTip, %myPath2%, %strWinId%
For pExp in ComObjCreate("Shell.Application").Windows
if (pExp.hwnd = strWinId)
try pExp.Navigate(myPath2)
return
Alt-1 works well. But, with Alt-2, the Navigate command returns "file:///C:/delete#me/ » not found.".
If there is no "/" after the "#" (eg myPath := "C:\delete#me"), it works. But this cannot be a solution because the destination path can be deeper in a subfolder (eg. "C:\delete#me\xyz").
I tried to encode the "#", replacing it with "%23", without success. Found nothing on the web or MSDN about that. Any idea?
[keywords: haskmark, hashtag, number sign or pound]
I have what looks to be a working solution for this, which I've also posted here:
4 options to change the current folder in Windows Explorer - Page 3 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=526&p=153676#p153676
;links:
;Explorer Windows Manipulations - Page 5 - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/19039-explorer-windows-manipulations/page-5#entry297581
;Navigate2 Method (IWebBrowser2)
;https://msdn.microsoft.com/en-us/library/aa752134(v=vs.85).aspx
;4 options to change the current folder in Windows Explorer - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=526
;windows - Navigate Shell command not working when the path includes an hash - Stack Overflow
;https://stackoverflow.com/questions/22868546/navigate-shell-command-not-working-when-the-path-includes-an-hash
;an AutoHotkey v1.1 script
;note: will create folder: %A_Desktop%\abc#def\abc#def
;q:: ;explorer - navigate to folder (tested on Windows 7)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, % "ahk_id " hWnd
if !(vWinClass = "CabinetWClass") && !(vWinClass = "ExploreWClass")
return
vDir = %A_Desktop%\abc#def\abc#def
;vDir = %A_Desktop%\abc def\abc def
if !FileExist(vDir)
FileCreateDir, % vDir
DllCall("shell32\SHParseDisplayName", WStr,vDir, Ptr,0, PtrP,vPIDL, UInt,0, Ptr,0)
for oWin in ComObjCreate("Shell.Application").Windows
if (oWin.HWND = hWnd)
{
if !InStr(vDir, "#")
oWin.Navigate(vDir)
else
{
VarSetCapacity(SAFEARRAY, A_PtrSize=8?32:24, 0)
NumPut(1, SAFEARRAY, 0, "UShort")
NumPut(1, SAFEARRAY, 4, "UShort")
NumPut(vPIDL, SAFEARRAY, A_PtrSize=8?16:12, "Ptr")
NumPut(DllCall("shell32\ILGetSize", Ptr,vPIDL, UInt), SAFEARRAY, A_PtrSize=8?24:16, "Int")
oWin.Navigate2(ComObject(0x2011,&SAFEARRAY))
DllCall("shell32\ILFree", Ptr,vPIDL)
}
break
}
return
If you want to open a new window, there's no need for COM or unreliable workarounds: just run the folder.
Run C:\delete#me
If you want to open the path in an existing window which is already active, the simplest and most effective workaround is this:
SendInput {F4}{Esc}{Raw}C:\delete#me`n
So in the context of your script, you could use the following function to work around the # when it is present:
Navigate(pExp, myPath2)
;...
Navigate(Exp, Path)
{
if RegExMatch(Path, "#.*\\")
SendInput {F4}{Esc}{Raw}%Path%`n
else
Exp.Navigate(Path)
}
Unfortunately, there does not seem to be a solution to this. Shell.Application Navigate command fails if the path includes a hash (# as in C:\C#Projects).
Using AutoHotkey, the workaround would be to rely on the "second best" approach as identified by the tests in this thread: http://ahkscript.org/boards/viewtopic.php?f=5&t=526.
run, Explorer.exe
Sleep, 500
strFolder := A_ScriptDir
Send, {F4}{Esc}
Sleep, 500
ControlSetText, Edit1, C:\delete#me, A
ControlSend, Edit1, {Enter}, A
When I saw that Navigate couldn't handle hash, I was shocked,
but sure enough I replicated the error.
I thought I'd try the short form path just in case. It works!
if vDir contains #
Loop, %vDir%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir := A_LoopFileShortPath
The following approach doesn't require a visible address bar, or SendInput,
also the previous navigation history is maintained.
In the worst-case scenario of a hash in the short-form path of the dir above the target dir,
a go-between folder is used which is navigated to.
A link is created there, invoked, and deleted.
Below, the workaround code is indented, to separate it from the standard code.
A hotkey of ctrl+q, when an Explorer window is active, launches the script.
-
^q:: ;explorer - navigate to directory (use go-between dir if short-form path of dir above target contains #)
WinGet, hWnd, ID, A
WinGetClass, vWinClass, ahk_id %hWnd%
if vWinClass not in CabinetWClass,ExploreWClass
Return
vDir2 = %A_Desktop%\Go-Between ;go-between dir
vDir3 = C:\delete#me ;target dir
if (SubStr(vDir3, 1-1) = "\")
vDir3 := SubStr(vDir3, 1, -1)
if !InStr(FileExist(vDir3), "D")
Return
vPathLnk := ""
if vDir3 contains #
Loop, %vDir3%, 2, 0 ;(0/1/2=files/both/folders, 0/1=recurse no/yes)
vDir3 := A_LoopFileShortPath
;vDir4 is the short-form path of the dir above the target
;paths of problem target dirs are of the form: *#*\*
;where there is at least one hash with a backslash to its right
SplitPath, vDir3, , vDir4
if vDir4 contains #
{
if !InStr(FileExist(vDir2), "D")
FileCreateDir, %vDir2%
if !InStr(FileExist(vDir2), "D")
{
MsgBox error`, go-between dir not found:`r`n%vDir2%
Return
}
vNameLnk = Go-Between.lnk
vPathLnk = %vDir2%\%vNameLnk%
FileCreateShortcut, %vDir3%, %vPathLnk%
}
for oWin in ComObjCreate("Shell.Application").Windows
if (hWnd = oWin.Hwnd)
{
vDir1 := oWin.Document.Folder.Self.Path
if (vDir1 = vDir3)
break
if vDir3 contains #
{
if !(vDir1 = vDir2)
oWin.Navigate(vDir2)
while !(oWin.ReadyState = 4)
Sleep 10
oItem := oWin.Document.Folder.Items.Item(vNameLnk)
oItem.InvokeVerbEx("open")
break
}
oWin.Navigate(vDir3)
break
}
oWin := ""
if !(vPathLnk = "")
FileRecycle, %vPathLnk% ;send to recycle bin
;if !(vPathLnk = "")
;FileDelete, %vPathLnk% ;delete
Return

Autohotkey script to open command prompt

I've collected a script from the AutoHotKey forum which lets me open a command prompt at the location I'm open in windows explorer. If the current window is not a explorer window then the prompt opens at the location where the script is present. I would like to change this behavior and make it open from C:\ if the current window is not a explorer window. I've tried to edit the script but its not working as desired.
#ifwinactive, ahk_class CabinetWClass
ControlGetText, address , edit1, ahk_class CabinetWClass
if (address <> "") {
Run, cmd.exe, %address%
}
else {
Run, cmd.exe, "C:"
}
ExitApp
#ifwinactive
The command to run cmd.exe in the c:\ path is
run, cmd.exe, c:\
A full script that would run the cmd window every time would look like this
SetTitleMatchMode, 2
ifwinactive, ahk_class CabinetWClass
ControlGetText, address , edit1, ahk_class CabinetWClass
else
address =
; Exclude specific windows
ifwinactive, My Computer
address =
ifwinactive, My Documents
address =
if (address <> "")
Run, cmd.exe, %address%
else
Run, cmd.exe, C:\
ExitApp
I realize this is an old question, but I was looking into this myself and have a better solution.
Windows has two in-built ways to start cmd at the path of a current explorer window. Shift+RightClick and then click Open Command Window Here (or press w). You can also press alt+d, type cmd, and press enter. So...
LWin & Return::
if WinActive("ahk_class CabinetWClass")
or WinActive("ahk_class ExploreWClass")
{
Send {Shift Down}{AppsKey}{Shift Up}
Sleep 10
Send w{enter}
}
else
{
run, cmd, C:\
}
return
No magically grabbing the address directly from explorer! :)
Couldn't get other answers to work (it has been a few years since they've been written).
I ended up writing this script:
#o::
Send {Alt down}D{Alt up}cmd{enter}
return
Here's a pretty sophisticated script from the AHK forums:
#NoEnv
#SingleInstance Force
#NoTrayIcon
SendMode Input
SetWorkingDir %A_ScriptDir%
SetTitleMatchMode RegEx
#IfWinActive ahk_class ExploreWClass|CabinetWClass|Progman
#c::
WinGetClass WinClass
If ( WinClass = "Progman" )
{
Run %ComSpec% /K cd /D "C:\"
Return
}
If ( InStr( "WIN_7,WIN_VISTA" , A_OSVersion ) )
{
ControlGetText, Path, ToolbarWindow322
RegExMatch(Path, ":\s*(.*)", Path)
Path := Path1
}
Else
{
; Windows XP doesn't know the Edit1 control exists if
; the Address Bar is hidden, so check if it exists and temporarly
; show the Address bar if needed. Temporarly showing the Address bar
; will register the Edit1 control, which contains the path.
ControlGetPos Edit1Pos , , , , Edit1
If ( !Edit1Pos )
{
PostMessage 0x111 , 41477 , 0 , , A ; Show Address Bar
Sleep 100
PostMessage 0x111 , 41477 , 0 , , A ; Hide Address Bar
}
ControlGetText Path , Edit1
}
If ( InStr( Path , ":" ) )
; If( InStr( Path , ":" ) && FileExist(Path) )
Run %ComSpec% /K cd /D "%Path%"
Else
Run %ComSpec% /K cd /D "C:\"
Return
I tweaked the WIN_7 part a little, so that the code is independent of the unreliable Edit1 control, which doesn't always expose the current explorer location or an incorrect one. If ( InStr( Path , ":" ) ) makes sure that there's no custom path like Computer on Windows 7 or My Computer on Windows XP. I also added an alternative condition that additionally checks for the path to exist, if you want to hedge your bets.
Keep it simple. Unless of course you need complexity.
!f1::
run, C:\Windows\System32\cmd.exe
return
!f1 means Alt+F1. For my personal preference. Change it to whatever you like.
Another solution hacked together from here. Works for me on Windows 10, but I admit it's total copy-pasta. Posting in the hopes of saving someone else's eyes from the horror of AHK scripting.
;; Open terminal in current Explorer window folder
#If WinActive("ahk_class CabinetWClass") ; explorer
F4::
WinGetTitle, ActiveTitle, A
If InStr(ActiveTitle, "\") ; If the full path is displayed in the title bar (Folder Options)
Fullpath := ActiveTitle
else
If InStr(ActiveTitle, ":") ; If the title displayed is something like "DriveName (C:)"
{
Fullpath := SubStr(ActiveTitle, -2)
Fullpath := SubStr(Fullpath, 1, -1)
}
else ; If the full path is NOT displayed in the title bar
; https://autohotkey.com/boards/viewtopic.php?p=28751#p28751
for window in ComObjCreate("Shell.Application").Windows
{
try Fullpath := window.Document.Folder.Self.Path
SplitPath, Fullpath, title
If (title = ActiveTitle)
break
}
Run, cmd.exe, %Fullpath%
return
#If

Can I add a custom paste option to the windows text editing context menu?

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.
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.
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.
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
}
;==================================================

Catch copy/paste of empty text on Windows from AutoHotKey script

By default on Windows, when copying text, it gets put in the clipboard. But when attempting to copy empty text, the clipboard is untouched. For example, selecting no text in your editor, then hitting ctrl+c, will cause no change in the clipboard.
Problem is, I need to catch this event with AutoHotKey. Since the clipboard is unchanged, I have no idea how to do this cleanly (without a timeout, that is).
Does anyone have any idea how to do this?
Edit: To clarify, I'm sending the ctrl+c from within AutoHotKey. I'm doing so to tell if any text is selected, i.e., I'm sending ctrl+c, then checking if any text was copied to the clipboard or not. Problem is, if no text is selected, the clipboard handlers for AutoHotKey never get called, forcing me to use a timeout, which isn't good practice.
Here is what I did. Since the clipboard is a variable in AutoHotkey, you can check to see if it is empty. I first cleared the clipboard, send control+c, then see if the clipboard is still empty. You can temporarily move the current clipboard to a temporary place first if you want.
ClipSaved := ClipboardAll
Clipboard = ; empties the clipboard
Send ^+{Left} ; I just used highlight left to select text, you can replace this with
; whatever your program uses to select an input.
Send ^c ; attempt to copy text
If Clipboard = ; checks to see if clipboard is empty
{
break ; Put what you want to do if the clipboard is empty, I used break to stop a loop
}
Clipboard := ClipSaved ; puts the original clipboard contents back
I was searching text from an open document in which the user can choose a forward or backward direction. When going backwards, it would get stuck in a loop at the beginning of the document. I set a loop limit to keep it from being an infinite loop, but it still wasted time having to wait for the loop to finish. I used the break function to end the loop if the clipboard was empty.
To give credit where credit is due, I got the inspiration from another post which had other tood tips. It posted you can check for a blank variable with this script.
http://www.autohotkey.net/~deleyd/xprxmp/autohotkey_expression_examples.htm#J
v := ""
If v =
MsgBox v = ""
If (v = "")
MsgBox v = ""
From the AutoHotkey documentation website I found out how to temporarily store and replace the clipboard content. http://www.autohotkey.com/docs/misc/Clipboard.htm
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
;... here make temporary use of the clipboard, such as for pasting Unicode text via Transform Unicode ...
Clipboard := ClipSaved ; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
ClipSaved = ; Free the memory in case the clipboard was very large.
Hope this helps.
Samuel
Here's the solution I currently use. Basically, it comes down to sending ctrl+c, waiting a certain timeout, then seeing if text was actually copied. If it wasn't, I know there is not selection.
There is no way, afaik, to avoid waiting a timeout, since Windows takes a certain time to perform the copy operation. I set the timeout to 0.15 seconds, so it isn't too bad.
Here's the function I use whenever I want to grab the contents of the clipboard, or check if it's empty. I always call this function first:
clipped_text :=
clip_empty := false
ClipSaved =
is_clipped := false
clip_speed := 0.15
Clip() {
global ClipSaved
global clip_empty
global clipped_text
global is_clipped
global clip_speed
if (!is_clipped) {
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
; msgbox % ClipSaved
is_clipped := true
}
clipboard = ; Empty the clipboard
Send ^{c}
ClipWait clip_speed
if (ErrorLevel = 1)
{
clip_empty := false
}
else
{
clip_empty := true
clipped_text := clipboard
}
}
And I use this function to actually get the contents of the clipboard or check if it's empty:
IsTextSelected() {
global ClipSaved
global clip_empty
global clipped_text
if (clip_empty == true) {
return true
}
else {
return false
}
}
To get the contents of the clipboard I just look at the clipped_text variable.
After performing a "Clip()" operation, I always call the following function to restore the clipboard (this function is called once for multiple calls of Clip()):
UnClip() {
global ClipSaved
global clip_empty
global clipped_text
global is_clipped
is_clipped := false
Clipboard := ClipSaved
ClipSaved =
}
While not an actual answer to this question, a google search might lead you here if you are looking for a way to catch text on paste and modify it before pasting.
Here's the script which eliminates whitespace from text pasted from clipboard on CTRL + V:
~^v::
Trimmed := RegExReplace(Clipboard, "^\s+", "")
Trimmed := RegExReplace(Trimmed, "\s+$", "")
Clipboard = %Trimmed%
SendInput ^v
return
I think I have a solution. Set aside current clipboard, then copy. Compare what you have copied to an empty string.. if it's equal, then something was copied; otherwise, nothing was copied. At then, restore the clipboard to what you saved. Here is a code sample demonstrating the principle.
^#x::
ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
; ... here make temporary use of the clipboard, such as for pasting Unicode text via Transform Unicode ...
Clipboard := ; Clear the clipboard
Send, {CTRLDOWN}c{CTRLUP}
if (Clipboard = "") {
Send, you copied nothing
} else {
Send, you copied something
}
Clipboard := ClipSaved ; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
ClipSaved = ; Free the memory in case the clipboard was very large.
return
Actually, I was hoping that there is another way to simply test if the cursor is currently selecting anything. I have asked this question on the AutoHotkey forums (http://www.autohotkey.com/forum/posting.php?mode=reply&t=69468), but until or if there is a better answer, I will use the above method.
Script for babylon (Middle Mouse Key for firefox):
MButton::
SetTitleMatchMode, 2
send {LButton}{LButton}
Send ^c
sleep, 100
send {F10}
sleep, 100
SendInput {Raw}%clipboard%
send {enter}
Return
I had the same problem - I would send the copy command, but it wouldn't copy anything. I tried working with timers to no avail.
Here is what I ended up doing (trying different modes):
thisclipboard := clipboard . a_now ;add NOW so that it won't possibly be the same as the contents of the clipboard
sendplay,^c
if(clipboard == thisclipboard){
sendinput,^c
}
if(clipboard == thisclipboard){
send,^c
}
Maybe you should hotkey the Ctrl + C instead, that way any time that hotkey is pressed you will know.
You might want to make sure to send the normal Ctrl + C action to windows so you can copy.
consider this example:
~^c::
msgbox, % "Clipboard Changed even if you didnt copy anything"
. "(...not really but you tried at least)"
return
That message will fire up every time you press Ctrl + C even if you didnt copy anything to the clipboard. At the same time you will be sending the native function of Ctrl + C to windows so your clipboard WILL change if you copied something.
From the help file:
~: When the hotkey fires, its key's native function will not be blocked (hidden from the system).
You might want to also have an onClipboardChange to check when the clipboard really changed.

Resources