Let's say I'm programming in a text editor and want to iterate a variable:
i++
Now, let's say for whatever reason, this language doesn't ++ but rather:
i = i + 1
this is annoying when you are used to the first syntax. I want a script which when receiving ++ translates this to a series of commands I send (control shift left arrow, etc, this is not the part I'm having trouble with).
However I cannot seem to get this method to execute:
+ & +::
Msgbox test
return
For whatever reason though, this is not fully being called - I do not see the keystroke for + when typing so I know it is somehow getting to that method, but, not registering the second +.
How can I call a method using the keystrokes ++ as a trigger?
There's a really great library called RegEx Powered Dynamic Hotstrings. And replacing someVar++ with someVar = someVar + 1 reeks of RegEx!
This one line will do what you want:
hotstrings("(\w+)\+\+", "%$1% = %$1% {+} 1")
This will work for every variable name that's alphanumeric (plus underscore): [a-zA-Z0-9_]
Of course, this won't work for every language since it strongly depends on the syntax. For example, some languages use := to assign expressions, other languages need a semicolon to complete a statement and so on...
Hotstrings WILL work for this occasion, however, you might need the "?" modifier for it to grab even within a "word" try it like this:
:*?:++::
ClipboardOld := ClipboardAll,Clipboard := ""
Send, +^{Left}^c
Clipwait
Send, ^{Right} = %Clipboard% {+} 1
Clipboard := ClipboardOld,ClipboardOld := ""
return
This also preserves the clipboard.
Related
As the title already says, I would like to copy and join any number of (mostly) non-adjacent words in any app (Web browser, E-Mail, MS Word, Editor, Evernote etc.). That is, any words that I (mouse-)select and copy hitting the 5-key while I simultaneously hold down the F4 key (but actually any hotkeys and modifiers that don't interfere with their normal functioning and which are also both easily and simultaneously reachable with the left hand would do).
This is what I came up with with my limited AHK-skills. The clipboard-part works, but for all I know not the global-variable (and therefore not the word-joining) nor the F4 Down & 5-hotkey-combo (without Down or without & 5 it technically would, though):
global MyString := "" ; make string global to keep contents between {5}-key presses
~F4 Down & 5:: ; copy any (non-adjacent) words with {5}-key as long as I hold down {F4}-key
clipboard := ""
Sleep 100
Send ^c
ClipWait, 1
MyString := MyString Trim(clipboard) ; append lastly copied word to any words copied before (while holding down {F4})
~F4 Up::
MsgBox, %MyString% ; show final string consisting of ALL copied words separated by a space
MyString := "" ; reset string
Return
Ultimately, I would like to copy %MyString% to the clipboard as one single long string rather than show it in a message box. I think I'm already near to the solution.
Can you solve it?
You're never ending the first hotkey's execution block, so its execution bleeds into the hotkey below and your MyString gets reset every time.
Also if you have an down/up hotkey pair, you don't specify the first down, only the up.
Also, there's no need to make your variable super-global.
Fixed script:
~F4 & 5::
Clipboard := ""
Sleep, 100
Send, ^c
ClipWait, 1
MyString := MyString " " Trim(Clipboard)
return
~F4 Up::
MsgBox, % MyString
MyString := ""
return
Pretty cool idea for a script btw. I might use something like this myself.
I want to set up a hotkey by pressing Alt, q and the Left arrow. So far I've tried
# opt 1
!q & Left::
#opt 2
Alt & q & Left::
# opt 3
!qLeft:: M
but the only result I get once I run the script is Error: invalid hotkey in the line above. There seems something is wrong with the ampersand.
I can share the whole script if needed.
According to the Custom Combinations section of the documentation:
Combinations of three or more keys are not supported.
However, I found this class that claims to
enable easy usage of custom multi-key hotkeys.
I haven't tested it myself, but if that hotkey is important to you, then it might be worth trying!
Here's a slightly janky solution using vanilla ahk and a timer.
Left::
If(keyPressed = 1){
...Do a thing...
}
return
!Q::
keyPressed := 1
SetTimer, altQTimer, 200
return
altQTimer:
keyPressed := 0
return
I am using hotstrings in AutoHotKey and the output is reliant on if characters are capitalized. Is there a way to determine if characters in the keys typed that triggered the hotkey are capitalized? I tried using A_ThisHotkey, but it does not seem to be case sensitive. Please let me know if you have a solution. Thanks.
I'm not aware of a built in way to do this, but maybe you'd be fine with just creating more hotstrings and using the C option for case sensitivity like this:
:C:hello::
:C:Hello::
:C:HeLLo::
:C:HELLO::
MsgBox, % A_ThisHotkey
return
Example request from comments:
hotstrings := "hello,HELLO,HeLlo,HellO,hElLo,hellO"
for each, hotstring in StrSplit(hotstrings, ",")
Hotstring(":CB0*?:" hotstring, Func("MyFunction"))
return
MyFunction()
{
MsgBox, % "Hotstring triggered!`n" A_ThisHotkey
}
You can activate the case sensitivity option before defining your Hotstrings
#Hotstring c
::Hello::Hi ; will be triggered only if you exactly typed these letters case-sensitive
In my main Autohotkey script I have several hundred hotstrings like these:
::fe::for example
::f::and
::fi::for instance
::fo::fortunate
::foy::fortunately
::glo::global
::gloy::globally
::ha::have
::hv::however
Fairly often it would be convenient to trigger a hotstring manually (e.g. by pressing ALT-9) rather than pressing and end character. Is there a way to do this? I haven't found anything in my Googling, so maybe there isn't. But it would be useful.
I've read the hotstrings options e.g. :*: but this isn't the same - I want normal hotstring operation, but also the option to manually force them to trigger as needed.
Updated:
So what you are in fact looking for is using ALT+9 as an end character. I'm not sure but you can probably not use key-combinations for that (see hotstring doc). I cannot think of a really clever way of doing that right now. You might try something like
::fe::
Transform, CtrlC, Chr, 3 ; comes from ahk input documentation, I never really understood how this is supposed to work but I guess there is a code for alt 9 as well somehow
input, key, L1 I M ; wait for the next 1 key
if(key==CtrlC)
sendraw forExample
return
Old answer:
You have to outsource the hotstring body:
::fe::gosub forExample
forExample:
send for example
return
, then you can define a hotkey somewhere:
!9::gosub forExample
If you want to be cool, use functions instead of subroutines.
Note:
::fe::something
is just a short form for
::fe::
send something
return
::fe::for example
::f::and
::fi::for instance
::fo::fortunate
::foy::fortunately
::glo::global
::gloy::globally
::ha::have
::hv::however
!8:: trigger_hotstring("fi")
!9:: trigger_hotstring("ha")
trigger_hotstring(hotstring){
Loop, Read, %A_ScriptFullPath%
{
If InStr(A_LoopReadLine, "::"hotstring "::")
{
SendInput, % StrSplit(A_LoopReadLine,"::"hotstring "::").2
break
}
}
}
If you use AutoHotkey v1.1.06+ you can use #InputLevel
::fe::for example
::f::and
; and so on
#InputLevel, 1 ; sending space will trigger hotstrings above this line
!F9::Send {space}
Edit:
I now see you want to omit the end char which needs a bit of extra work
One way would be to duplicate the hotstrings with additional options:
::fe::for example
:*O:fe_::for example ; duplicate the hotstrings like so
::f::and
::fi::for instance
::fo::fortunate
; and so on
#InputLevel, 1
!9::Send _
Another way would be to remove the endchar
::fe::for example
::f::and
::fi::for instance
::fo::fortunate
; and so on
#InputLevel, 1
!9::
Send {space}
Sleep 100 ; give it time to expand the hotstring, experiment with timing
Send {bs} ; now remove trailing space
Return
I generally use TAB as a trigger for all my hotstrings. like
:*:#pm ::mail1#protonmail.com
:*:#G ::mail2#gmail.com
:*:Btw ::By the way,{Left}
Note that the space that you see here is a tab and not a space. you can do this instead of doing Alt+9 to trigger your macro hotstring.
you can even use more than one Tab so you can be sure that you only trigger it when you really intend to.
Here's my AHK script
:*:if ::
SendInput IF{Space}
Input cond, I V T5,, then
msgbox %ErrorLevel%
msgbox %cond%
if (ErrorLevel = "Match")
{
SendInput {Enter}End If{Space}'%cond%
}
Return
When I type If x = 1 then I get an ErrorLevel of 'Timeout' and a cond of 'x = 1 then'
My understanding is that when I type then it's supposed to stop the Input and set the ErrorLevel to Match.
I've tried putting it in quotes, using single letters in the MatchList, and including and end key, but none of works. The few examples I could find of using MathList look just like mine.
Input cond, I V T5 *,,% " then"
Without the asterisk option, an item in MatchList needs to be the next thing typed. So If Then would match then in the MatchList. But If anything then doesn't match then in the MatchList because it's trying to match anything then, not just then.
With the asterisk option, if anything then is matched because the next thing typed after If contained then. That causes problems if you type if heathen then because the then in heathen triggers it. The space before then should fix that, but it doesn't.
AHK help says that the MatchList respects spaces, but it doesn't seem to do that when the space is before the first (or only) item in MatchList. The two ways around that are to include a dummy word at the beginning or to use the % thingy to quote the MathList item and include the space.
See also http://ahkscript.org/boards/viewtopic.php?f=5&t=3979
I strongly recommend using RegEx powered hotstrings for this purpose:
#Include <Hotstrings>
hotstrings("if (.*?) then", "If %$1% then``nEnd If%A_SPACE%")
The definition of "T" in the AutoHotkey Help File states this:
T: Timeout (e.g. T3). The number of seconds to wait before terminating the
Input and setting ErrorLevel to the word Timeout. If the Input times out,
OutputVar will be set to whatever text the user had time to enter.
Basically, this is saying exactly what is to be expected (and what is actually happening) with your script. So, for me when I type "if x = 1 then" my "if" is immediately replaced with the caps lock IF and a space.
After 5 seconds, the first MsgBox appears with "Timeout" as the text (again, expected since ErrorLevel is set to the word "Timeout" when the "T" option is present). Once that MsgBox is dismissed, I receive the second MsgBox which (according to the help file) contains OutputVar which is what I (the user) had time to enter in before the Timeout.