How to pass window title to user function in AutoHotKey - autohotkey

I want to pass the window title into a function I wrote in AutoHotKey, is window title WinTitle a string? I have 4 window titles, and I need to pass them to the same function.
Extract(my_window_title) {
; Wake and select the correct window to be in focus
WinWait, my_window_title,
IfWinNotActive, my_window_title, , WinActivate, my_window_title,
WinWaitActive, my_window_title,
; ... do a bunch of things
}
I call the function like this
title1 = "Some title"
Extract(title1)
and I also tried putting % in all the variables

Yes WinTitle is basically a string.
Check out your Autohotkey-folder, there should be a file called "AU3_Spy.exe". Use it to find the window titles.
And as Elliot DeNolf already mentioned, you made some mistakes with variables. You should also take another look at the syntax of IfWInNotActive.
This should work:
Extract(my_window_title) {
; Wake and select the correct window to be in focus
WinWait, %my_window_title%
IfWinNotActive, %my_window_title%
{
WinActivate, %my_window_title%
WinWaitActive, %my_window_title%
}
msgbox, %my_window_title%
; ... do a bunch of things
}
title1 = MyWindowTitle
Extract(title1) ;functions always expect variables, no percent-signs here

There are a few things that look like they are causing an issue in your script.
When assigning a string value and using =, quotes are not needed. If you assign the value using :=, then you need the quotes. These 2 lines are equivalent:
title1 := "Some Title"
title1 = Some Title
Once these values are called via a function ie. Extract(title1), % symbols must be used (as you mentioned at the end of your question). This can be called in 2 ways:
WinActivate, %my_window_title%
WinActivate, % my_window_title
If the title is invalid, your script will wait indefinitely on WinWait and WinWaitActive. I would recommend using a timeout value and then checking ErrorLevel to see if it was successful or not.

Related

Autohotkey: Define a hotkey and passthrough it to system dynamically, how to?

I'm facing a somewhat hard question. Look at this script:
; Using Autohotkey 1.1.36.2
F2::
send_f2_withcond()
{
if(WinExist("ahk_class Notepad"))
{
ControlSend Edit1, % A_Now "`r", % "ahk_class Notepad"
}
else
{
; I hope F2 can do its original action. How to?
Send {$F2} ; ??? No effect!
}
}
My purpose:
If there is Notepad running, F2 will send some text to Notepad.
If Notepad is not running, I hope F2 can do it original action, for example, pressing F2 in an Explorer window will start renaming current highlighted file.
Writing Send {F2} is not correct, because it will trigger my own F2:: ... action recursively.
The doc says adding a $ prefix will suppress recursive calling, BUT, Send {$F2} takes no effect(as if I totally omit this Send), the current active application receives only F2's WM_KEYUP, no WM_KEYDOWN.
The $ prefix is used only in hotkey definitions. It forces the keyboard hook to be used, which is designed to filter out keys sent by AutoHotkey scripts.
$F2:: send_f2_withcond()
send_f2_withcond() {
if WinExist("ahk_class Notepad")
ControlSend, Edit1, % A_Now "`r", % "ahk_class Notepad"
else
Send {F2}
}
You can greatly simplify this script by using #IfWinExist.
#IfWinExist, ahk_class Notepad
F2::ControlSend Edit1, % A_Now "`r", % "ahk_class Notepad"
#IfWinExist

Why autohotkey deos not send Ctrl-Space where Space is an input

Consider the following assignment:
When I type - followed by a key, the result is Ctrl-key. This work for ordinary keys.
But when the key is whitespace, it does not work.
Any idea why this happens? And how to fix the code?
-::
Input, key, L1,{LCtrl}
send, ^{%key%}
return
Edit.
Try to run the above script a program which has Ctrl-Space as a shortcut to see that it does not work. In fact, if you press - followed by Space, the script is suppose to call Ctrl-Space but it is not the case. For example:
In Microsoft Excel or in Libreoffice Calc, Ctrl-Space can select the current column.
In Emacs Ctrl-Space is reserved for setting a Mark.
Use SendInput instead.
Tested in Excel to mimic ^a, ^x, ^v, ^space
-::
Input, key, L1,{LCtrl}
SendInput, ^%key%
Return
If you want to handle "special" keys, add those keys to the list of endkeys using this syntax
Input [, OutputVar, Options, EndKeys, MatchList]
And then check to see which endkey was pressed
Tested in Firefox to mimic ^PgDn, ^PgUp
Input, key, L1,{LCtrl}{PgUp}{PgDn}
If (ErrorLevel = "EndKey:PgUp") {
SendInput ^{PgUp}
}
Else If (ErrorLevel = "EndKey:PgDn") {
SendInput ^{PgDn}
}
Else If (ErrorLevel = "EndKey:LCtrl") {
Return ;assumed you just want to abort input with the control key
}
Else {
SendInput, ^%key%
}
Return

Autohotkey: Toggle caps lock on/off on activating certain windows

I want to write a script that will turn on caps lock when I activate a window containing particular keyword in its title(like SQL). I also want the caps lock to be turned off when I switch to a window whose title does not contain any of the keywords that I have specified.
How can I do it? I have considered #Persistent with a timer to periodically check active window. But, I think there should be a better way.
check answers at: http://www.reddit.com/r/AutoHotkey/comments/1qjf83/force_specific_program_to_use_caps/. Especially G33kDude's answer. It's a clever and efficient solution: check of current window is binded only to windows activation.
=======================
Edit: Code inserted below.
Please note that it's not a complete solution, you'll need to make some edits for your needs. Not a big ones, though.
#Persistent ; Don't close when the auto-execute ends
SetTitleMatchMode, 2 ; Partial title matching
WinGet, myHwnd, ID, Notepad ; Get the handle to the your window
; Listen for activation messages to all windows
DllCall("CoInitialize", "uint", 0)
if (!hWinEventHook := DllCall("SetWinEventHook", "uint", 0x3, "uint", 0x3, "uint", 0, "uint", RegisterCallback("HookProc"), "uint", 0, "uint", 0, "uint", 0))
{
MsgBox, Error creating shell hook
Exitapp
}
;MsgBox, Hook made
;DllCall("UnhookWinEvent", "uint", hWinEventHook) ; Remove the message listening hook
return
; Handle the messages we hooked on to
HookProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime)
{
global myHwnd
static lastHwnd
WinGetTitle, title, ahk_id %hwnd%
if (hwnd == myHwnd) ; If our window was just activated
{
tooltip, Gained focus
}
else if (lastHwnd == myHwnd) ; If our window was just deactivated
{
tooltip, Lost focus
}
lastHwnd := hwnd
}
If you want to do this without using SetTimer, the best way would be to use context-sensitive hotkeys. For Example:
SetTitleMatchMode, 2
#If WinActive("SQL") or WinActive("Notepad")
a::A
b::B
c::C
d::D
e::E
;; etc.
You could also use the WinActive function with Window Groups instead of the title if you wanted to avoid a very long #If line.
EDIT: Case-Insensitive Example
SetTitleMatchMode, Regex
GroupAdd, Editor, (?i).*sql ; Regular expression for window title
GroupAdd, Editor, (?i).*ahk
#IfWinActive ahk_group Editor
a::A
b::B
c::C
d::D
e::E
;; etc.
Since you have a Autoit in your tag, here is how it is done easy in autoit.
Opt("SendCapslockMode", 0)
While 1
Sleep(200)
$title = WinGetTitle("", ""); will get the title of the active window
If StringInStr($title, "sql") Then
Send("{CAPSLOCK ON}")
Else
Send("{CAPSLOCK OFF}")
EndIf
WEnd
Milos' answer is quite straight forward, but it misses a vital point. You need to set SendCapslockMode to 0. Else the effect of the Send command will be useless, because after the command the original state will be restored.
The next thing is, you don't need to use an infinite loop with a Sleep which will execute the complete loop body every few milliseconds, but you can wait for the active window to not be active any more, which is less CPU intensive. So a fully working solution in AutoIt is:
Opt("SendCapslockMode", 0)
While True
$win = WinGetHandle("[ACTIVE]")
If StringInStr(WinGetTitle($win), "sql") Then
Send("{CAPSLOCK ON}")
Else
Send("{CAPSLOCK OFF}")
EndIf
WinWaitNotActive($win)
WEnd
#Persistent
SetTitleMatchMode, 2 ; use RegEx for finer control
Loop
{
WinWaitActive, Notepad
{
WinGet, opVar, ID
SetCapsLockState, On
}
WinWaitNotActive, ahk_id %opVar%
SetCapsLockState, Off
}
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; This script solves the problem of forgetting to turn on or off the capslock when using specific programs
; I for one ALWAYS use capital letters when typing things in CAD. My problem was when switching to another
; program, usually e-mail, I'd start typing and then have to erase it. Problem solved!
; The beauty of this script is that you don't lose the ability to manually turn the capslock on or off
; My first few interations of this script would turn it on when in the CAD window but then
; I'd never be able to turn it on wihtout it being forced off again.
Loop {
state := GetKeyState("Capslock", "T") ; check toggle state, save in variable 'state'
if state = 0
status = Off ; this block converts the 1 or 0 of variable 'state'
if state = 1 ; into the word ON or OFF and stores it in variable 'status'
status = On
Beginsub:
WinGetTitle, Title, A ; retreive current window title, store in Title
if title contains AutoCAD 2012 ; if title contains "AutoCAD" turn on capslock
; then go back to the BeginSub subroutine and see if the title
{ SetCapsLockState, on ; still matches "AutoCAD 2012" if it does not...\/\/\/
goto, BeginSub
}
SetCapsLockState, %status% ; ...Put caps lock back to the state it was when we started.
; 'SetCapsLockState' doesn't recognize a 1/0 variable
; therefore the use of 'status' and ON/OFF words
Sleep, 1000 ; only check every second
}

How to get window handle by PID in autohotkey?

I want to get window handle by PID in autohotkey, because title of the window is always changing. If anyone wonder, I want to get handle of last.fm main window.
To get the first window Class/ID of a PID you can do the following:
Process, Exist, "notepad.exe"
NewPID = %ErrorLevel% ; Save the value immediately since ErrorLevel is often changed.
if NewPID
{ ; process exists!
WinGetClass, ClassID, ahk_pid %NewPID% ; ClassID will be read here for the process
WinGetTitle, Title, ahk_pid %NewPID% ; Title will contain the processe's first window's title
IfWinExist ahk_class %ClassID% ; this will find the first window by the ClassID
{
WinGet, WinID, ID ; this will get the ID of the window into WinID variable
WinActivate ; this will bring this window to front (not necessary for example)
ListVars ; this will display your variables
Pause
}
IfWinExist %Title% ; this will find the first window with the window title
{
WinGet, WinID, ID
WinActivate ; this will bring this window to front (not necessary for example)
ListVars
Pause
}
}
there are other methods to convert the PID other than IfWinExist I'm sure, and it is possible to have more than one process with same class ID. :)
Additionally you can use
As a reusable function:
getHwndForPid(pid) {
pidStr := "ahk_pid " . pid
WinGet, hWnd, ID, %pidStr%
return hWnd
}
You can use the WinGet command with the Cmd paramter as ID.
Cmd is the operation to perform, which if blank defaults to ID.
ID: Retrieves the unique ID number of a window. Also known as the window handle (HWND).
WinTitle can be a PID.
WinGet, UniqueID, ID, ahk_pid %VarContainingPID%
Another option is WinExist()
UniqueID := WinExist("ahk_pid" . VarContainingPID)

How to get the active window's title with AutoHotKey?

I wrote this short test code, but it didn't work. What am I doing wrong?
F12::
WinGetTitle, Title, A ;
MsgBox, "%Title%"
The displayed result was ""
I removed a ; and added return and this worked...
F12::
WinGetTitle, title, A
MsgBox, "%title%"
return
The best practice would probably be to use WinGetActiveTitle:
F12::
WinGetActiveTitle, Title
MsgBox, The active window is "%Title%".
return
If you do not put in a return it will run down your whole file.
Probably something not running through later in it.
Don't think the ; will affect it.
Anything after a ; is omitted from code as a comment.
Using WinGetActiveTitle or WinGetTitle will do.
Note the output of WinGetTitle contains more than the window title.
You might want to remove the ending part with the program name e.g." - Google Chrome".
WinGetActiveTitle, Title
StringGetPos,pos,Title,%A_space%-,R
if (pos != -1)
Title := SubStr(Title,1,pos)
In AutoHotKey 2 you can use this:
title := WinGetTitle("A") ; "A" matches "Active" window
In AutoHotKey 1 you can use:
WinGetActiveTitle, title