SendInput inside If condition in AutoHotKey - autohotkey

Im using autohotkey to fix my keyboard that is typing the character 'y' when I type the character 't'. That is , when I press 't' in my keyboard, 'ty' gets typed. Here is the code I came up with. Im new to autohotkey but I am familiar with a few programming languages.
timeout := 50 ;ms
t::
{
SetTimer, ResetMonitoring, % -timeout
monitor := true
}
return
#If monitor
y::
{
SendInput t
return
}
#If
ResetMonitoring:
{
monitor := false
return
}
But the 't' from SendInput never gets typed. So instead of 'ty', now, nothing gets typed when this script is running. I tried putting a message box there instead of SendInput, and it works so I know that the script reaches that line when y is detected after t.
I used this line for MessageBox
MsgBox, % "Your next press was: " . A_ThisHotkey
I receive a message box with message as "Your next press was: y".
What am I doing wrong?

Without having ran your code, I see one issue. y:: Sends t and will therefore trigger t::. To avoid triggering keys from within your code, add $ in front of the key.
$y::
$t::

Related

How to make script to paste something in with AutoHotKey

I'm trying to make a script in AutoHotkey where, when I press Numpad 1, it presses the slash button, then pastes in some text, let's say "hello world", and then presses enter, but I can't figure out how. Can someone help?
Welcome to Stack Overflow.
In the future, try to at least show what you tried. All of this should be accomplished pretty easily by e.g. looking at the beginner tutorial combined with a quick Google search.
But well, here it is:
Numpad1::
Clipboard := "/hello word"
SendInput, ^v{Enter}
return
Numpad1:: creates the hotkey label.
Clipboard:= ... puts something into the clipboard.
SendInput sends input.
^v means Ctrl+v.
{Enter} means the enter key (could've possibly appended `n (line feed) into the string as well).
Return stops the hotkey label's code execution (in other words, ends the hotkey's code).
Assuming that you already have some text copied inside your clipboard before pressing the numpad1, the following code will work.
Numpad1::
Send, /^v ; ^ means ctrl key,
Send, {Enter}
return

What in this script is causing my window to minimize?

The goal of this simple script is to detect an idle interval when a specific program is in focus and then send a simple keystroke when that idle interval has passed. I'm running this script on 4 PC's and I'm getting unexpected results. Some PC's minimize the window when the script runs. Other PC's run it as expected. The script is identical on each PC.
I'm invoking this script by right clicking on the script (that is, not running a compiled exe version of it). Running it as administrator seems to achieve better results on some clients, on one it makes no difference and minimizes the window.
As stated, on some PC's the script works as intended. There are no error messages, it just causes my window to minimize. Nothing in that code, to my newb eyes, should cause the window to minimize.
#Persistent
SetTimer, Timer_check,3000
Timer_check:
if WinActive("ahk_exe gta5.exe")
{
if (A_TimeIdlePhysical > 31301 && WinActive("ahk_exe gta5.exe")) {
Gosub, keepActive
ToolTip, We're currently idle TimeIdle is %A_TimeIdle% and TimeIdlePhysical is %A_TimeIdlePhysical%
sleep 1000
ToolTip
}
if (A_TimeIdle < 31301) {
ToolTip
}
}
return
keepActive: ; keep active sub.
if WinActive("ahk_exe gta5.exe")
{
Send, {` down} ; Press the ` key to keep us active. It holds the key for 0.2 seconds.
Sleep 200
Send, {` up}
}
return```
You're trying to send the accent/backtick, which is default escape character in AHK (`). To fix this, send a different character or escape the escape character, like so:
Send, {`` down}
Sleep 200
Send, {`` up}
Without it being escaped, it just sends the down- and up-keys. The WinKey+down combination minimizes a non-maximized window and that may somehow be related to why you're seeing the game window occasionally minimized.
https://www.autohotkey.com/docs/commands/_EscapeChar.htm
Edit: Added script for testing
#Persistent
SetTimer, Timer_check, 3000
Timer_check:
If WinActive("ahk_exe gta5.exe") {
If (A_TimeIdlePhysical > 31301 && WinActive("ahk_exe gta5.exe")) {
Send , z
ToolTip, We're currently idle TimeIdle is %A_TimeIdle% and TimeIdlePhysical is %A_TimeIdlePhysical%
sleep 1000
ToolTip
}
If (A_TimeIdle < 31301)
ToolTip
}
Return

How do I delete the current line using AutoHotkey?

Using an AutoHotkey script I'd like to set the keyboard command Ctrl+D to delete the current line in any active Windows app.
How?
^d::Send {Home}{ShiftDown}{End}{Right}{ShiftUp}{Del}
Might not work in all edge cases, but passes some very basic testing in Notepad. =~)
HaveSpacesuit's answer works but after using it for a while I realized it deletes the active line and sometimes re-positions the spacing of the line below.
This led me to rethink his solution. Instead of going from the front of the line to the back, I tried going from back to front. This solved the re-positioning issue.
SendInput {End}
SendInput +{Home}
SendInput ^+{Left}
SendInput {Delete}
There is still a small problem though. If the cursor is on an empty line, with more empty lines above, then all empty lines get deleted.
I don't know a key combo to replace ^+{Left} that doesn't have this behavior so I had to write a more comprehensive solution.
^d:: DeleteCurrentLine()
DeleteCurrentLine() {
SendInput {End}
SendInput +{Home}
If get_SelectedText() = "" {
; On an empty line.
SendInput {Delete}
} Else {
SendInput ^+{Left}
SendInput {Delete}
}
}
get_SelectedText() {
; See if selection can be captured without using the clipboard.
WinActive("A")
ControlGetFocus ctrl
ControlGet selectedText, Selected,, %ctrl%
;If not, use the clipboard as a fallback.
If (selectedText = "") {
originalClipboard := ClipboardAll ; Store current clipboard.
Clipboard := ""
SendInput ^c
ClipWait .2
selectedText := ClipBoard
ClipBoard := originalClipboard
}
Return selectedText
}
As far as I can tell this produces no unexpected behaviour.
However, be careful if you're using a clipboard manager as this script uses the clipboard, if necessary, as an intermediary to get the selected text. This will impact clipboard manager history.
In case you run into problems where you need different behaviours for different programs, you can "duplicate" your ^d command for specific programs like this:
SetTitleMatchMode, 2 ; Makes the #IfWinActive name searching flexible
^d::Send {Home}{ShiftDown}{End}{Right}{ShiftUp}{Del} ; Generic response to ^d.
#IfWinActive, Gmail ; Gmail specific response
^d::Send {Home}{ShiftDown}{End}{Right}{ShiftUp}{Del} ; adapt this line for gmail
#IfWinActive ; End of Gmail's specific response to ^d
#IfWinActive, Excel ; Excel specific response.
^d::Send {Home}{ShiftDown}{End}{Right}{ShiftUp}{Del} ; adapt this line for Excel
#IfWinActive ; End of Excel's specific response to ^d
This way your ^d command will work differently in Excel and Gmail.
I have a simple way to solve the repositioning issue. Without using the clipboard.
The repositioning issue is due to the need to handle 2 separate cases.
if there's existing text in a line,
we want to select them all, and delete the text (backspace 1)
and backspace one more time to delete the empty line (backspace 2)
if it's a blank line,
we want to delete the empty line (backspace 1)
To cater for both of above cases, I introduced a dummy character.
This will make sure BOTH cases will act the same way.
So doing backspace 2 times, will result in the same transformation each time.
Simply,
; enable delete line shortcut
^d::
Send {Home}
Send {Shift Down}{End}{Shift Up}
Send d
Send {Backspace 2}
Send {down}
return
Disadvantage with this approach,
the dummy character "d" will appear when you undo. Not a bad tradeoff since I don't undo delete lines very often.

Toggle keys in autohotkey

My goal is mapping WASD to the 4 arrow buttons on the keyboard and make 1 'Suspend' the script while z exits it. That was easy enough. Now I'd like a and d only apply conditionally. I look at the docs and I have no idea what's wrong here. I think I'm either using the if statement wrong or Left/Right doesn't work in if statements in which case I have no idea what to do.
#SingleInstance
a::if(UseAD) Left
d::if(UseAD) Right
1::Suspend
2::UseAD:=!UseAD
w::Up
s::Down
z::ExitApp
Try this:
#SingleInstance
$a::Send % UseAD ? "{Left}" : "a"
$d::Send % UseAD ? "{Right}" : "d"
1::Suspend
2::UseAD:=!UseAD
w::Up
s::Down
z::ExitApp
Okay now a break down.
Your If statement wasn't being evaluated correctly. The following line of code after the condition is met is what is run. Like so:
If (true)
do this
Your Hotkey is also wrong for a Multi lined statement. Essentially a single lined Hotkey is a basically a Send command for whatever key or keys specified on that line (unless you specify an assignment/function/command etc...) it will act as a Send Command does. To have an If evaluation requires multiple lines. When you specify a hotkey and you want an evaluation that will require multiple lines you, and must return from a Multi-Lined Hotkey same a Sub Routine:
a::
Code goes here
more code
etc..
Return
b::AnotherHotkey
etc..
Okay so lets plug this Logic in with your code:
#SingleInstance
a::
if(UseAD)
Left
return
d::
if(UseAD)
Right
return
1::Suspend
2::UseAD:=!UseAD
w::Up
s::Down
z::ExitApp
If you run this you'll get an Error about the Text Left... that is because instead of our Hotkey acting as Send command it's acting as a Sub Routine so we have to specify Send command with Left:
a::
if(UseAD)
Send, Left
return
But this isn't correct either, now it's sending the word Left instead of the Key left.. so again we have add Brackets around our named key like so:
a::
if(UseAD)
Send, {Left}
return
Okay, now a and b are not being sent when UseAD is False, so we must Send them by specifying with Else like so:
a::
if(UseAD)
Send, {Left}
else
Send, a
return
Now we run this code and press a or b get an Max Hotkeys reached message because our code is triggering the Hotkey in an Infinate loop. We need to specify our code in such a way that it will not trigger itself, like so:
$a::
if(UseAD)
Send, {Left}
else
Send, a
return
If you notice we have added a $ symbol in front of our hotkey, this adds a keyboard Hook to that Hotkey and will prevent the the script from triggering that hotkey itself. This is now a complete working script but looks entirely different from the first code I posted. That is because I like typing less lines, if I can.
In the first code sample I'm using a Forced Expression % on the Send command and Ternary ? : to evaluate UseAD and if true send Left key if false send the letter, exactly the same as above code, just more concise.

Is it possible to create a macro like that with AHK?

I'm something like a GM in a MMORPG game. Our job is reporting people who using cheat and sending them to jail. But leaving that jail zone is not really hard so we have to send them again and again. I have a loooong nickname list (I have about 400 nicknames to report repeatly) so It's really boring.
What i wanna ask is, I don't know anything about AHK. If that kind of macro is possible, I'll do a loooong research to create that macro. But if It's not possible, I'm not even gonna try.
What i need is; The Macro will press "enter" to activate chat mode. Then will write "/report -cheater nickname-" and remember there's 400+ nicknames exist so I need to repeat the macro for different nicknames. After it write "/report -cheater nickname-" Macro will press enter. Then a little chat box will pop-up. Macro will click to the box, will write the report reason, then click confirm. then another chat box will pop-up to say something like "your report is received." And macro will click to confirm for that too. And will do it for 400+ nicknames with 400+ different reasons. Is that actually possible to do? Just wondering that. Not asking you to creating this macro. If you answer that, I'll try to make it myself :D
Thanks.
This script is to perform a series of searches on Google. The search strings are stored in a text file and read into an array, they are then executed one by one, based on hitting the {Tab} key (you can make this repeat automatically).
When the script is interrupted, you can start it again and give it a (new) starting number, or tell it to start from 1 again.
Not exactly what you were looking for, but it gives you a lot of starting points.
#Persistent
#SingleInstance Force
#installKeybdHook
SetWorkingDir %A_ScriptDir%
TempDir = C:\Temp
Menu, Tray, Icon , %A_AhkPath%, 2, 1
TrayTip, JobSearch, Started, 1
SetTitleMatchMode, 2
TextCounter = 0
Return
+Launch_App1::
Run, Notepad %TempDir%\Google.txt
Return
Launch_App1:: ; vacatures Job Search
+CapsLock::
Restart:
MouseGetPos, XPos2, YPos2
XPos3 := 50
YPos3 := 100
IniRead, TextCounter, %TempDir%\GoogleCounter.ini, Counter, Nr
ArrayCount = 0
Loop, Read, %TempDir%\Google.txt ; This loop retrieves each line from the file, one at a time.
{
ArrayCount += 1 ; Keep track of how many items are in the array.
Array%ArrayCount% := A_LoopReadLine ; Store this line in the next array element.
}
MaxSearchCount = %ArrayCount%
TextCounter += 1
If (TextCounter > 1)
InputBox, TextCounter , Start, Number (1..%MaxSearchCount%),,,,,,,10,%TextCounter% ; InputBox, OutputVar [, Title, Prompt, HIDE, Width, Height, X, Y, Font, Timeout, Default]
TextCounter += 0
IniWrite, %TextCounter%, %TempDir%\GoogleCounter.ini, Counter, Nr
SearchText:=Array%TextCounter%
MouseClick, left
gosub, SendNewSearch
Return
;=======================================================================================================================================
Browser_Favorites:: ; Search for next Vacature string (Vacatures)
CapsLock::
If (TextCounter = 0) ; Restart with previous script if Textcounter is set to 0
{
GoSub, Restart
Exit
}
IniRead, TextCounter, %TempDir%\GoogleCounter.ini, Counter, Nr
TextCounter += 1
IniWrite, %TextCounter%, %TempDir%\GoogleCounter.ini, Counter, Nr
SearchText:=Array%TextCounter%
If (SearchText = "")
{
TextCounter := 0
IniWrite, %TextCounter%, %TempDir%\GoogleCounter.ini, Counter, Nr
Send, ^{F4}
SplashTextOff
ExitApp
}
Sleep, 200
Send, {Home 2}
Sleep, 700
Send, {WheelUp 10}
Sleep, 400
gosub, SendNewSearch
Exit
SendNewSearch:
MouseGetPos, XPos3 ,YPos3
SetTitleMatchMode, 2
IfWinActive, Chrome
{
while (A_Cursor = "AppStarting")
Sleep, 200 ; Continue
Sleep, 100
SplashTextOff
MouseClick, left, %XPos2%,%YPos2%
WinGetTitle, this_title, A
IfInString, this_title, Google
{
Send, {Home}+{End}{DEL}%SearchText%{Enter}
}
ToolTip, Waiting....
DisplayText = Nr%TextCounter% %SearchText%
Sleep, 500
SplashTextOn, 200, 0,%DisplayText%
WinMove, %DisplayText%, , 800, 25
ToolTip
;MouseMove,(50),(500)
MouseMove,%XPos3%,%YPos3%
ClipBoard = %SearchText%
}
Exit
Exit
+Browser_Favorites::
run, %TempDir%\Google.txt
Return
It is possible to do. You can create two txt files which have list of +400 user names and +400 different reasons. Macro can read lines one by one and can makes all things, what you want, more than 400 times.
You will need this loop for writing lines from txt file to an array, a loop in a function for checking expected color at the specified pixel with PixelGetColor (http://www.autohotkey.com/docs/commands/PixelGetColor.htm) for detecting buttons. You may also use PixelGetColor command or AutoIt3 Window Spy, which will be installed with autohotkey, to see colors of buttons. Finally you can start to code from here (http://www.autohotkey.com/docs/).
PS. Sorry, site did not allow me to use more than 2 hyperlinks.
Basically you are trying to write a script that types enter, then a list of characters then enter again?
Something quite simple you could do would be to create a .txt file that includes everything you want it to type (excluding enters, except between lines), and create a macro like this:
#n::
Loop, Read, inputFile.txt
{
Send {Enter}%A_LoopReadLine%{Enter}
}
return
Basically you run the macro and open the game to the point that you can start typing enter, character information, enter, but press the windows key and the 'n' key. The macro would then loop through each line of 'inputFile.txt' and stimulate typing an enter, the line, and then an enter.