AHK Script using PostClick and PostMessage - autohotkey

I'm trying to write a simple AHK script to type a few characters and make a few clicks at specific coordinates in a background window, but I can't seem to get it to work, and I'm not finding a lot of information on how to properly use PostClick.
I was able to get this to work using Click when the window is active. Also tried using ControlClick, which seemed to work, except the click was happening on the location where the mouse was rather than the coordinates provided (and also only when the window was activated again).
Can I please have some help / advice on how to get this to work?
Here's my current script:
DetectHiddenWindows On
S:: ;Character to start the loop
pid = 19164 ;Application PID
ControlGet, clickVar, Hwnd , , ahk_pid %pid% ;Specify control for which program
BreakLoop = 0
Loop, 3 {
if (BreakLoop = 1)
break
Sleep 1000
PostClick(clickVar,1055,525)
{
ControlSend,, 3, ahk_pid %pid%
lParam := x & 0xFFFF | (y & 0xFFFF) << 16
PostMessage, 0x201, , %lParam%, , ahk_pid %pid% ;WM_LBUTTONDOWN
PostMessage, 0x202, , %lParam%, , ahk_pid %pid% ;WM_LBUTTONUP
}
Sleep 1500
}
E::
BreakLoop = 1
return
Thanks ahead of time for the help.

I am going to assume you are attempting to use this function.
I am unsure how this function works, but I think what you want is something like:
DetectHiddenWindows On
S:: ;Character to start the loop
pid = 19164 ;Application PID
ControlGet, clickVar, Hwnd , , ahk_pid %pid% ;Specify control for which program
WinGetTitle, clickTitle, ahk_pid %pid%
WinGetClass, clickClass, ahk_pid %pid%
BreakLoop = 0
Loop, 3
{
if (BreakLoop = 1)
break
Sleep 1000
PostClick(1055,525,clickClass, clickTitle)
ControlSend,, 3, ahk_pid %pid%
Sleep 1500
}
E::
BreakLoop = 1
return
PostClick(x, y, class, title)
{
lParam := x & 0xFFFF | (y & 0xFFFF) << 16
PostMessage, 0x201, 1, %lParam%, %class%, %title% ;WM_LBUTTONDOWN
PostMessage, 0x202, 0, %lParam%, %class%, %title% ;WM_LBUTTONUP
}
You need to place the function somewhere in the same file or at least accessible by the current file. You can do #include <script name here>.ahk at the top of your file and place that function as a new file in the same directory if you want.
The function you are trying to use takes in an x and a y for where to click in that window. Then it also takes in a class and title in order to know which window to actually use. Hope this works or helps you in some way.

Related

AHK with command ^!ENTER::Send {Media_Play_Pause} doesn't work in Windows 11

I want to be able to play and stop a Youtube Video using Auto Hot Key while I am using the Vs Code editor, without the need to stop and play the video with the mouse. That will save some time.Any help would be appreciated.
I can rewind back and forth, but I want to be able to play/pause it as well.
^!ENTER::Send {Media_Play_Pause} ( Only this command does Not work )
So far I have this script:
#SingleInstance, Force
SetTitleMatchMode, 2
SetBatchLines, -1
SetWinDelay, -1
^!ENTER::Send {Media_Play_Pause} ; ( Only this command does Not work )
^!Left::
WinGet, Current_Window, ID, A
WinActivate, - YouTube
ControlGetPos, conX, conY, , , ChromeRenderWidgetHostHWD1
ControlClick,, A,,,, % " X" (conX+1) " Y" (conY+1)
ControlSend, , {Left 3}, A
WinActivate, % "AHK_ID" Current_Window
return
^!Right::
WinGet, Current_Window, ID, A
WinActivate, - YouTube
ControlGetPos, conX, conY, , , ChromeRenderWidgetHostHWD1
ControlClick,, A,,,, % " X" (conX+1) " Y" (conY+1)
ControlSend, , {Right 3}, A
WinActivate, % "AHK_ID" Current_Window
return

How to activate a Script only if a specific Window is active?

I have a problem with a Script which should just do the following:
- If a specific Window becomes active
- SetCapslockState, On
- If the Windows lost focus
- SetCapslockState, Off
I've tried:
#If WinActive("ahk_class blahblah")
SetCapslockState, On
and/or
#If !WinActive("ahk_class Chrome_WidgetWin_1")
SetCapslockState, Off
But it don't work.
Also I've tried:
WinWaitActive, (mytitleofwindow)
if ErrorLevel
{
SetCapslockState, On
return
}
else
It don't work either, else I would not ask for help here... hihihi
I hope someone can help me! :)
Instead of a loop (which takes up CPU cycles), you can also use Hardware Handles. See example:
#SingleInstance Force
#installKeybdHook
#Persistent
Menu, Tray, Tip, Medical Alert
SetKeyDelay, 50
Menu, Tray, Icon , Shell32.dll, 145, 1
TrayTip, Medical Alert, Started, 1
Gui +LastFound
hWnd := WinExist()
DllCall( "RegisterShellHookWindow", UInt,Hwnd )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
Return
ShellMessage( wParam ) ; Run on Window switch
{
If (wParam = 4) ; If Window Changed
{
WinGetActiveTitle, Title
if instr(Title, "Past Medical History") OR instr(Title, "Allergies Verified") ; TESTED WITH: if instr(Title, "NotePad")
MsgBox, 1, Allergies Verified, Please verify patient allergies
}
}
Return
The key is to combine WinWait[Not]Active with a Loop.
Loop {
WinWaitActive, mytitleofwindow
SetCapslockState, On
WinWaitNotActive, mytitleofwindow
SetCapslockState, Off
}

ControlSend not sending to the non-topmost window

Is it possible to make ControlSend send / click to a background window?
This code finds a window by id / handler, but sends a click / keystroke only if the window is the topmost. ControlSend skips its action if the window is not topmost. ControlClick force brings window to top and then clicks.
#Singleinstance
DetectHiddenWindows, On
#SingleInstance Force
#MaxThreadsPerHotkey, 2
SendMode Input ; Recommended for new scripts
SetControlDelay -1
PostClick(x,y,win="A") {
lParam := x & 0xFFFF | (y & 0xFFFF) << 16
PostMessage, 0x201, , %lParam%, , %win% ;WM_LBUTTONDOWN
PostMessage, 0x202, , %lParam%, , %win% ;WM_LBUTTONUP
}
RunAsAdmin() {
Loop, %0% {
param := %A_Index% ; Fetch the contents of the variable whose name is contained in A_Index.
params .= A_Space . param
}
ShellExecute := A_IsUnicode ? "shell32\ShellExecute":"shell32\ShellExecuteA"
if not A_IsAdmin
{
If A_IsCompiled
DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_ScriptFullPath, str, params , str, A_WorkingDir, int, 1)
Else
DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_AhkPath, str, """" . A_ScriptFullPath . """" . A_Space . params, str, A_WorkingDir, int, 1)
ExitApp
}
}
RunAsAdmin()
F1::
Loop
{
; http://particle-clicker.web.cern.ch/particle-clicker/
WinGet, WinID, ID, Particle Clicker - Google Chrome
; Send keystrokes only if tab active and topmost, suspend if focus lost, continue when gain focue
; ControlSend, ahk_parent, {Space}, ahk_id %WinID%
; send clicks only if tab not mininised, if tab on background - force bring it to front
; ControlClick, x799 y449, ahk_id %WinID%
; same as above
; ControlClick, x799 y449, ahk_id %WinID%,,,,NA
; same as above
; Controlclick x799 y449,ahk_id %WinID%,,Left,1,NA
; same as above
PostClick(799,449,"Particle Clicker - Google Chrome")
sleep 1000
}
return
F12::ExitApp

Typing on two windows at the same time

I want to be able to select both window 1 and window 2 and be able to type on both windows at the same time.
Whatever I type in window 1 will be typed in window 2 as well, for example: "hey everyone".
Being able to type on both windows at the same time, having both selected for typing. I have 2 notepad windows open. I want to type on the the first notepad window I opened, and what ever I type on window 1 will also be typed on window 2.
Sadly, I can't put up a image for you can see what I'm trying to say
WinGet, windowid, List, <Name of Window goes here>
#IfWinActive, <Name of Window goes here>
Space:: ; jump
KeyWait, Space, D
ControlSend,, {Space} , ahk_id %windowid1%
ControlSend,, {Space} , ahk_id %windowid2%
ControlSend,, {Space} , ahk_id %windowid3%
ControlSend,, {Space} , ahk_id %windowid4%
ControlSend,, {Space} , ahk_id %windowid5%
Return
I'm not sure if I even understand what you're trying to do... but have you tried using Input?
loop {
input, char, I L1 V M
ControlSend,, %char%, ahk_id %windowid1%
}
For example: Catching every single character sent in any %processID% window by Input and sending it to all remaining %processID% windows afterwards:
processID := "notepad.exe"
loop {
input, char, I L1 V M
winGet, active_win_ID, ID, A
winGet, active_win_exe, ProcessName, A
winGet, windowsToBeSentTo_IDs, List, ahk_exe %processID%
if active_win_exe != %processID%
continue
loop, %windowsToBeSentTo_IDs% {
_id := windowsToBeSentTo_IDs%a_index%
if _id != %active_win_ID%
controlSend,, %char%, ahk_id %_id%
}
}

WinMinimize PID after MsgBox

The following code opens notepad, then minimizes it. It works fine:
!^m::
Run, Notepad.exe,,USEERRORLEVEL MAX, PID
WinWait, ahk_pid %pid%
WinMinimize, ahk_pid %PID%
return
However if I add an MsgBox to display the PID before minimizing the notepad window, then the latter doesn't get minimized:
!^m::
Run, Notepad.exe,,USEERRORLEVEL MAX, PID
WinWait, ahk_pid %pid%
MsgBox OK %PID%
WinMinimize, ahk_pid %PID%
return
Why?
Sleeping didn't help:
!^m::
Run, Notepad.exe,,USEERRORLEVEL MAX, PID
WinWait, ahk_pid %pid%
MsgBox OK %PID%
Sleep, 2000 ; 2 seconds
WinMinimize, ahk_pid %PID%
return
I use Windows 7 SP1 x64 Ultimate and AHK 1.1.13.01 (October 11, 2013). I have the same issue with Version v1.0.48.05 and Version v1.1.15.02. All AHK versions I tried are 32-bit.
Edit:
!^b::WinMinimize, ahk_pid 9156 doesn't even work. (9156 being a valid PID)
Following MCL suggestion, I also unsuccessfully tried:
!^t::
PID = 11692
hwnd := WinExist("ahk_pid " pid)
WinMinimize, ahk_id %hwnd%
return
Use this code (it is tested and is working):
!^m::
Run, Notepad.exe,,MAX, PID
CheckWin:
IfWinExist, Untitled - Notepad
{
WinWait, Untitled - Notepad
MsgBox OK %PID%
WinMinimize, Untitled - Notepad
}
else
{
Goto, CheckWin
}
return
WinWait and WinMinimize commands cannot use Process ID (PID). In my code I am using WinTitle with these commands.
I am using IfWinExist command to be sure that notepad.exe is already launched and only after use WinWait and WinMinimize commands.