Hotkey to toggle another hotkey into a different function or mode - autohotkey

I'm trying to get a the hotkey LCTRL to toggle XButton2 into different modes.
The issue is that it's saying that there are duplicate hotkeys in the same script. I clearly don't know what's going on. Help?
~LCtrl::
actioncameratoggle := !actioncameratoggle
if actioncameratoggle
{
~XButton2::
rTurn := !rTurn
if rTurn
{
send {lctrl}
mousemove, 800, 450
send {ctrl}
mousemove, 1600, 450
}
else
{
}
}
else
{
~XButton2::
{
}
}
return
Thanks!

With your Script You can not toggle with the same hotkeys, the reason is you want to use the if with the Else commands > if hotkey1:: else hotkey1::, you will need the #if commands. Look to this example code.
You can Write this example.ahk Code and try it out on your Windows System.
Change the code a little bit for your needs, and it is done.
I did make the script so that the other guys can simple test it out.
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
a := 1
#If mode1 ; All hotkeys below this line will only work if mode1 is TRUE or 1
t::1
; Here you can put your first hotkey code ~XButton2::
#If
#If mode2 ; All hotkeys below this line will only work if mode2 is TRUE or 1
t::2
; And here you can put your second hotkey code ~XButton2::
#If
; toggle between [t::1] and [t::2]
;a = 1 => t::1
;a = 2 => t::2
;type LCtrl key to toggle between two the same hotkeys
;you can test it out in notepad - if you then type the key t
~LCtrl::
if (a=1)
{
mode1 = 1
mode2 = 0
a := 2
}else{
mode1 = 0
mode2 = 1
a := 1
}

Related

Script in AutoHotkey to Press Windows button and Left Arrow simultaneously

I want to write a script in autohotkey so that every time I open my dictionary application on PC, keys Windows+LeftArrow being pressed at the same time and as the result, it snaps the windows on the left side of monitor.
I tried this:
#IfWinActive Oxford Advanced Learner's Dictionary
Send, #{Left}
return
Also this one:
#IfWinActive Oxford Advanced Learner's Dictionary
Send, {LWinDown}{Left}{LWinup}
return
But for either of them noting happened when I opened the application.
EDIT:
As suggested by #Charlie Armstrong the real question is: How do I make a block of code run every time I start a certain program? So #IfWinActive might not be useful for.
One way is periodically check if new process/window is created and to check if that is a process/window we want to interact with.
This first example is based on COM notifications when a process has been created/destroyed.
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:04 2021/02/28)
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
NewProcess_CheckInterval := 1 ; in seconds
SetTitleMatchMode, 2 ;this might not be needed, makes the check for "contains" instead of "same" winTitle
hWnds := []
gosub, initialize_NewProcessNotification
return
; Called when a new process is detected
On_NewProcess(proc) {
global hWnds
global MyWatchedWindowTitle
; get the window handle, if possible
if (hwnd:=WinExist("ahk_pid " proc.ProcessID)) {
WinGetTitle, wTitle, ahk_id %hwnd%
; check if there is a visible window
if (wTitle)
{
; if so, check if it's a window we want to interact with
if (InStr(wTitle,MyWatchedWindowTitle))
{
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds, hwnd)) {
; we havent, so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet, MonitorWorkArea, MonitorWorkArea
posY := 0
posX := 0
width := A_ScreenWidth // 2
height := MonitorWorkAreaBottom
WinMove, ahk_id %hwnd% ,,%posX%,%posY%,%width%,%height%
; multi-montitor support, more examples, and more complete snapping functions can be found here:
; https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc
}
ArrayContains(haystack, needle) {
for k, v in haystack
{
if (v == needle)
return true
}
return false
}
initialize_NewProcessNotification:
;////////////////////////////// New Process notificaton ////////////////////////
; from Lexikos' example
; https://autohotkey.com/board/topic/56984-new-process-notifier/#entry358038
; Get WMI service object.
winmgmts := ComObjGet("winmgmts:")
; Create sink objects for receiving event noficiations.
ComObjConnect(createSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessCreate_")
ComObjConnect(deleteSink := ComObjCreate("WbemScripting.SWbemSink"), "ProcessDelete_")
; Set event polling interval, in seconds.
interval := NewProcess_CheckInterval
; Register for process creation notifications:
winmgmts.ExecNotificationQueryAsync(createSink
, "Select * from __InstanceCreationEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Register for process deletion notifications:
winmgmts.ExecNotificationQueryAsync(deleteSink
, "Select * from __InstanceDeletionEvent"
. " within " interval
. " where TargetInstance isa 'Win32_Process'")
; Don't exit automatically.
#Persistent
return
; Called when a new process is detected:
ProcessCreate_OnObjectReady(obj) {
proc := obj.TargetInstance
/*
TrayTip New Process Detected, % "
(LTrim
ID:`t" proc.ProcessID "
Parent:`t" proc.ParentProcessID "
Name:`t" proc.Name "
Path:`t" proc.ExecutablePath "
Command line (requires XP or later):
" proc.CommandLine
)
*/
On_NewProcess(proc)
}
; Called when a process terminates:
ProcessDelete_OnObjectReady(prm) {
/*
obj := COM_DispGetParam(prm, 0, 9)
proc := COM_Invoke(obj, "TargetInstance")
COM_Release(obj)
TrayTip Process Terminated, % "
(LTrim
ID:`t" COM_Invoke(proc, "Handle") "
Name:`t" COM_Invoke(proc, "Name")
)
COM_Release(proc)
*/
}
This second example, which is perhaps a bit simpler, checks periodically for new windows that match the searched WinTitle.
; help for question: https://stackoverflow.com/q/66394326/883015
; by joedf (16:17 2021/02/28)
#Persistent
MyWatchedWindowTitle := "Oxford Advanced Learner's Dictionary"
SetTitleMatchMode, 2 ;this might not be needed, makes the check for "contains" instead of "same" winTitle
SetTimer, checkForNewWindow, 1000 ;ms
hWnds := []
return
checkForNewWindow() {
global hWnds
global MyWatchedWindowTitle
; first check if there is at least one window that matches our winTitle
if (hwnd:=WinExist(MyWatchedWindowTitle)) {
; get all window matches
WinGet, wArray, List , %MyWatchedWindowTitle%
; loop through all windows that matched
loop % wArray
{
hWnd := wArray%A_Index%
; check if we've interacted with this specific window before
if (!ArrayContains(hWnds, hwnd)) {
; we havent, so we do something with it
hWnds.push(hwnd) ; keep in memory that we have interacted with this window ID before.
DoSomething(hwnd) ; the keys we want to send to it
}
}
}
}
DoSomething(hwnd) {
; size and move window to the left
SysGet, MonitorWorkArea, MonitorWorkArea
posY := 0
posX := 0
width := A_ScreenWidth // 2
height := MonitorWorkAreaBottom
WinMove, ahk_id %hwnd% ,,%posX%,%posY%,%width%,%height%
; multi-montitor support, more examples, and more complete snapping functions can be found here:
; https://gist.github.com/AWMooreCO/1ef708055a11862ca9dc
}
ArrayContains(haystack, needle) {
for k, v in haystack
{
if (v == needle)
return true
}
return false
}
I think your biggest issue is that AHK doesn't seem to work well for snapping windows (according to my quick research and testing). What does work well, though, is WinMove.
I assume you're launching the program from a shortcut icon, but I would suggest using a keyboard shortcut that launches the program and then positions the window from the script. Here is some sample code that opens Notepad2.exe, waits for 200 milliseconds, and then moves the window and resizes it:
^+!n:: ; Control+Shift+Alt+N to Open Notepad
Run C:\Program Files\Notepad2\Notepad2.exe
sleep, 200
WinMove, Notepad2,, 10, 20, 800, 600
return

How to achieve visual-studio-like chained hotkeys using AHK?

I'm trying to achieve a visual-studio-like chaining of hotkeys for something at work.
Basically, when I hit Ctrl+Alt+F, I want to enter a sort of "Format mode" The next key I press will determine what text is injected. I'd like "Format mode" to cease as soon as one of the inner hotkeys is pressed. However I'd also like the option to have to cancel it manually just in case.
I've tried searching for the chaining of hotkeys, as well as attempted the following, rather naive code:
;
;; Format Mode
;
^+f::
; Bold
b::
Send "<b></b>"
Send {Left 4}
return
; Italics
i::
Send "<i></i>"
Send {Left 4}
return
; Bulleted List
u::
Send "<u></u>"
Send {Left 4}
return
; Numbered List
o::
Send "<o></o>"
Send {Left 4}
return
; List Item
l::
Send "<li></li>"
Send {Left 4}
return
; Line Break
r::
Send "<br/>"
return
return
I was pretty sure this wasn't going to work, but I figured I'd give it a shot so as to not make y'all think I'm just asking to be spoon fed.
I haven't worked with AHK a whole lot, but I've used it enough to be able to accomplish some stuff both at home and at work, but it's suuuuper messy - just as some background as to my experience with AHK.
With the #if command you are able to Switch/Toggle between action1/Enable and action2/Disable with the same Hotkeys.
You can test it out in Notepad. if you then type the key t
type Ctrl+Shift+f keys to toggle between two the same hotkeys.
Note: For your Hotkeys You Can Change the Code a Little Bit! you can Place all your hotkeys into #if Mode1 and then use no hotkeys into #if Mode2
Example1.ahk
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
#SingleInstance force
a := 1
#If mode1 ; All hotkeys below this line will only work if mode1 is TRUE or 1
t::
send 1
; Here you can put your first hotkey code
return
; Here you can Place All your Hotkeys
#If
#If mode2 ; All hotkeys below this line will only work if mode2 is TRUE or 1
t::
send 2
; And here you can put your second hotkey code
return
#If
; toggle between [t::1] and [t::2]
;a = 1 => t::1
;a = 2 => t::2
;type Ctrl+Shift+f keys to toggle between two the same hotkeys
;you can test it out in notepad - if you then type the key t
^+f::
if (a=1)
{
mode1 = 1
mode2 = 0
a := 2
}else{
mode1 = 0
mode2 = 1
a := 1
}
return
esc::exitapp
Using #If is a good choice, as stevecody showed. Below is another solution that may work for you. It uses your ^+f hotkey to activate the specialty hotkeys. The specialty hotkeys will also deactivate themselves upon use. f1 is your option to cancel it manually.
^+f::
Hotkey , b , l_Bold , On
Hotkey , i , l_Italics , On
Hotkey , l , l_ListItem , On
Return
f1::
Hotkey , b , l_Bold , Off
Hotkey , i , l_Italics , Off
Hotkey , l , l_ListItem , Off
Return
l_Bold:
Hotkey , b , l_Bold , Off
Send , <b></b>{left 4}
Return
l_Italics:
Hotkey , i , l_Italics , Off
Send , <i></i>{left 4}
Return
l_Italics:
Hotkey , l , l_ListItem , Off
Send , <li></li>{left 5}
Return
Something else I was looking at, but it doesn't quite work right, is below. The problem is that it will still send the specialty key and you end up with something like <i>i</i> instead of <i></i>.
f1::
KeyBdHook := DllCall( "SetWindowsHookEx" , "int" , 13 , "uint" , RegisterCallback( "KeyBdProc" ) , "uint" , 0 , "uint" , 0 )
input
Return
KeyBdProc( nCode , wParam , lParam )
{
global KeyBdHook
Critical
If ( wParam = 0x100 )
{
DllCall( "UnhookWindowsHookEx" , "ptr" , KeyBdHook )
sKey := GetKeyName( Format( "vk{:x}" , NumGet( lParam + 0 , 0 , "int" ) ) )
If ( sKey = "i" )
Send , <i></i>{left 4}
Else
MsgBox , You pressed %sKey%
}
}

AHK blocked input

So I am making my script
toggl:=false
while(1){
if(toggl){
Send,E
}
Sleep, 150
}
!r::
toggl:=!toggl
return
!y::ExitApp,101
Problem is that while the loop is running, I can not cancel it because it blocks !y, so I had to restart computer. So any help with this would be nice.
Set #MaxThreads 2 to allow each hotkey to run twice, OR:
Use SetTimer to allow the hotkey to end and continue your loop in a "Pseudo-Thread".
toggle := 0
F12::
toggle := !toggle
if (toggle){
SetTimer, DoLoop, -100
}
return
DoLoop:
Loop {
if (!toggle){
break
}
; [Do your stuff here]
}
return

Can someone help me with this AHK Script

I want this Autohotkey script to press the spacebar automatically with a toggle option so i dont have to hold the spacebar all the time. The toggle key should be the middle mouse button. Could you please write it correctly for me? Because the toggle part I found doesn't seem to work. Thanks in advance CptPrice :D
Main script:
*~$Space::
Sleep 100
Loop
{
GetKeyState, SpaceState, Space, P
If SpaceState = U
break
Sleep 5
Send, {Blind}{Space}
}
Toggle-part:
#MaxThreadsPerHotkey 2
MButton::
if (toggle := !toggle) {
; on
} else {
; off
}
return
toggle := false
return
MButton:: toggle := !toggle
#If toggle
#MaxThreadsPerHotkey 2
*~$Space::
Sleep 100
Loop
{
Sleep 5
Send, {Blind}{Space}
if (!toggle) ; Press MButton to break
break
}
return
#If

Autohotkey Application Keycounter

I am trying to create an application based Key counter. Below is my script
#UseHook
KeyCount=0
#If WinActive("Ahk_Class XLMAIN") Or WinActive("Ahk_Class Notepad")
Loop
{
Input, Key, L1 I V, ,
AscKey:=Asc(Key)
If (AscKey > 31 && AscKey < 127)
KeyCount:=KeyCount+1
}
#If
^+o::
msgbox %KeyCount%
return
As the WinActive commands says it should count keystrokes if active window is either Excel or notepad. But this script counts all keystrokes. Am I missing something?
You don't use the #if its only for hotkeys and hotstrings but you can use a normal if statment like this
#UseHook
KeyCount=0
Loop
{
Input, Key, L1 I V
If (WinActive("Ahk_Class XLMAIN") Or WinActive("Ahk_Class Notepad"))
{
AscKey:=Asc(Key)
If (AscKey > 31 && AscKey < 127)
KeyCount++
}
}
^+o::
msgbox %KeyCount%
return
Hope it helps