How to create context-sensitive hotkeys when no window is active? - windows

I want to create some hotkeys when no window is active:
But there's no statement like #IfNoWinActive, how to achieve this?

There is always an active window (the one that will get input).
E.g. the Win+X Menu has no title but a hidden ahk_class (LauncherTipWnd). To detect it you have to add DetectHiddenWindows, On in your script:
#NoEnv
#SingleInstance Force
DetectHiddenWindows, On
#IfWinActive ahk_class LauncherTipWnd ; Win+X Menu
F1:: Run notepad
F2:: Send m ; starts the Device Manager
#IfWinActive
EDIT:
To get the title and ahk_class of the (hidden) active window, run this script and press F1 as soon as that window is active:
#NoEnv
#SingleInstance Force
DetectHiddenWindows, On
F1::
WinGetTitle, ActiveTitle, A
WinGetClass, ActiveClass, A
MsgBox, ActiveTitle: %ActiveTitle%`nActiveClass: ahk_class %ActiveClass%
return
F2::
WinSetTitle, A, , NewTitle
WinGetTitle, ActiveTitle, A
MsgBox, ActiveTitle: %ActiveTitle%
return
F3::
WinGet, ActiveExe, ProcessName, A
MsgBox, ProcessName: "%ActiveExe%"
return
Press Ctrl+C to copy the content of the MsgBox.
EDIT2:
In case the active window has no title and no ahk_class you can try this:
F1::
WinGetTitle, ActiveTitle, A
WinGetClass, ActiveClass, A
If (ActiveTitle = "" && ActiveClass = "")
Run notepad
; else If WinActive("WinTitle ahk_class WinClass", "WinText", "ExcludeTitlePart")
; do this
else
Send {F1}
Return

~Esc::
WinGet A, PID, A
if !A {
MsgBox ; 👈 put logic here
}
return

Related

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

I want to add an entry to the context menu of a text field, eg:
I have an AutoHotkey executable that will put highlighted text into the clipboard, then execute a Google search in Chrome with the clipboard. I would like a registry addition that gives me a single-click in the menu, that runs that executable. I have achieved this in the Explorer context menu (for processing of files with third-party applications, etc), but I have found no mention anywhere of the ability to change this specific menu.
The question asks how to edit the context menu for an Edit control,
and provides an image showing an Edit control context menu, present
while renaming a file in Explorer.
One approach would be to show a custom context menu,
when an Edit control is right-clicked,
or when an Edit control is focused and the AppsKey is pressed.
The AutoHotkey script below provides such functionality
for Explorer (tested on Windows 7), it replicates
the Edit control menu and adds a button that opens the selected
text in the default web browser.
Note: The Explorer address bar also uses an Edit control,
however, this is taken into account by the script.
;AutoHotkey script for:
;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
;see also:
;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
;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") && !InStr(A_ThisLabel, "MyItem")
{
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 0 ;this comments out the 6 lines below
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 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%"
;Run, chrome.exe "%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
}
;==================================================
I will describe editing a file's menu first, and then editing an Edit control's menu afterwards.
File's menu:
If you know how to safely use RegEdit,
creating this registry entry, will add the option 'My Script' to the right-click context menu for all files:
HKEY_CLASSES_ROOT\*\Shell\My Script\command
(Default) REG_SZ "C:\Program Files\AutoHotkey\AutoHotkey.exe" "C:\Program Files\AutoHotkey\My Script.ahk" "%1"
Clicking on the menu item will launch the script.
If you want to do something to the file that was clicked, it's path can be retrieved via:
vPath = %1%
To operate on more than one file at the same time requires a shell extension, which is more complicated.
Edit control's menu:
The context menu in your image is an Edit control's context menu.
To change that menu would be more difficult. When you rename a file, you are editing text on a small Edit control.
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 on top, and you would probably want to recreate the Undo/Cut/Copy/Paste/Delete/Select All items that operate on the Edit control. Using ControlGet, vText, Selected to recreate the Copy function for example. You would also need to capture right-clicks via the RButton hotkey, 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 some 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
;Menu Google Search Autohotkey script: select any text in any text edit field, then press
AppsKey & RButton::
^+g:: ; or press Ctrl+Shift+g
Menu,GoogleSearch,Add,Search with Google,GoogleSearch
Menu,GoogleSearch,Show
return
GoogleSearch:
{
Send, ^c
Sleep 50
Run, http://www.google.com/search?q=%clipboard%
Return
}

AutoHotkey able to capture firefox tab?

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

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

Autohotkey - How to link a GUI to a window to act the same as its parent

I would like to link a GUI to a certain window, so it could act like it's a part of it.
This is my GUI and I would like it to follow the Calculator (for testing). If the calculator is minimized, the gui would be minimized as well.
Thanks in advance!
#SingleInstance Force
#Persistent
BC = 0
Gui, Color, EEAA99
Gui, Margin , 0, 0
GUI, +AlwaysOnTop -Border -SysMenu -Caption +ToolWindow +Owner
Gui, Font, S48 CDefault Bold CBlue, Verdana
Gui, Add, Text, BackgroundTrans , Units completed:
Gui, Font, S72 CDefault Bold CGreen, Verdana
Gui, Add, Text, BackgroundTrans vBuildCounter, %BC%
WinSet, TransColor, EEAA99
Gui +LastFound +AlwaysOnTop +ToolWindow
WinSet, TransColor, EEAA99
Gui -Caption
Gui, Show, % "x" A_ScreenWidth - 400 " y" A_ScreenHeight / 4
:?*:asd:: ;count up
SoundBeep, 500,500
BC := BC += 1
GuiControl,, BuildCounter, %BC%
Return
:?*:qwe:: ;reset the counter
SoundBeep, 500,500
BC := 0
GuiControl,, BuildCounter, %BC%
Return
Esc::
ExitApp
I ended up with two scripts. Maybe this can be combined later.
One script is for the ToolMenu, the second for the activation.
Since I could not control the GUI, Show/Hide from the Activation script, I "solved" it by using Ctrl+Alt+Win+F1 and Ctrl+Alt+Win+F2.Not the most elegant way, but it works...
ToolMenu.ahk
#SingleInstance Force
#installKeybdHook
#Persistent
Gui, Destroy
Gui,+AlwaysOnTop
Gui,+ToolWindow
Gui,+Border
Gui, Add, Button, y5 w60, &LowBeep
Gui, Add, Button, y5 w60, &HighBeep
Gui, Add, Button, y8 h18, X
Gui, Show, y0, MyToolWindow
Return
ButtonLowBeep:
SoundBeep, 300, 300
Return
ButtonHighBeep:
SoundBeep, 500, 300
Return
ButtonX:
ButtonCancel:
Gui, Destroy
ExitApp
^!#F1::
Gui, Hide
Return
^!#F2::
Gui, Show, y0, MyToolWindow
Return
DetectWindowChange.ahk
#SingleInstance
#installKeybdHook
#Persistent
Global SwitchCounter
Gui +LastFound
hWnd := WinExist()
DllCall( "RegisterShellHookWindow", UInt,Hwnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return
ShellMessage( wParam )
{
If (wParam = 4)
{
WinGetTitle, CurrName, A
If (CurrName = "Calculator" OR CurrName = "MyToolWindow")
{
If ( SwitchCounter = 0)
{
;WinRestore, MyToolWindow
Send, ^!#{F2} ; Send Ctrl+Alt+Win+F2 to trigger GUI Show in GUI script
}
SwitchCounter += 1
}
Else
{
If ( SwitchCounter > 0)
{
;WinMinimize, MyToolWindow
Send, ^!#{F1} ; Send Ctrl+Alt+Win+F1 to trigger GUI Hide in GUI script
}
SwitchCounter := 0
}
}
}
Return
Let me know how this works...
You can (as far as I know) only do this with a settimer.
Pseudo code, not tested!
SetTitleMatchMode := 2
SetTimer, CheckWindow, 200
CheckWindow:
If WinActive("Calculator")
{
Gui, Show, % "x" A_ScreenWidth - 400 " y" A_ScreenHeight / 4, Popup
}
Else If !WinActive("Popup")
{
Gui, Hide
}
Return
Edit: Added a condition to avoid hiding the popup if it is activated.

Resources