Toggle between keyboard shortcuts with AutoHotKey - autohotkey

I am trying to map a key to toggle between two different shortcuts. The purpose is to easily switch between desktops in Windows 10 (instead of having to press three buttons)
What I am trying is:
toggle := false
½:: Toggle = false ? ( ^#Right, Toggle := true ) : ( ^#Left, Toggle := false )
She script runs without errors, but it does not work.
Can someone give me a hint?

It should be send ^#Right, but you cannot put extra commands into the ternary operator. You may only specify a value to be stored into toggle (as shown here).
Toggle = false ? ... has to be Toggle := false ? ..., for the right-hand side is an expression, not a string.
Try
%::
toggle := !toggle
if(toggle)
send ^#{Right}
else
send ^#{Left}
return
I personally can't think of a more compact way of doing it, which you obviously want to achieve.

If you want to toggle with more then two [Keyboard Shortcuts] toggle's,
you can use this AHK code.
Example1.ahk
; [+ = Shift] [! = Alt] [^ = Ctrl] [# = Win]
#SingleInstance ignore
a := 1
; If you want to toggle with more the two toggle's you can use this code.
;a = 1 => send {^#Right}
;a = 2 => send {^#Left}
;a = 3 => send {????}
;click the f1 key to toggle
f1::
if (a=1)
{
Menu, Tray, Icon,c:\icons\32x32\icon1.ico,1,1 ; change tray icon
send {^#Right}
a := 2
}else{
if (a=2)
{
Menu, Tray, Icon,c:\icons\32x32\icon2.ico,1,1 ; change tray icon
send {^#Left}
a := 3
}else{
if (a=3)
{
Menu, Tray, Icon,c:\icons\32x32\icon3.ico,1,1 ; change tray icon
;send {????}
a := 1
}}}
return
esc::exitapp

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

Hotkey to toggle another hotkey into a different function or mode

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
}

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

AHK: remap numeric keypad with Numlock On so it behaves like numeric keypad with Numlock Off

I'd like to remap the numeric keypad with Numlock On to behave like the numeric keypad with Numlock Off, including being able to extend the selection with Shift/Ctrl held down.
The problem I have is the following
Numpad8::Up
Doesn't have correct behaviour when shift+numpad8 is pressed, the cursor moves up, but no text is selected. The following also don't work as I'd like (same behaviour as Numpad::8).
+Numpad8::Up
+Numpad8::+Up
If I remap a normal key, the selection behaviour is correct when shift is pressed:
w::Up
Any hints?
The reason I'm doing this is to make a CoolerMaster QuickFire TK's numeric keypad behave like it has a standard numeric keypad layout (I've some registry keyboard remapping happening as well, which is why I want the navigation behaviour with Numlock On).
It's possible, but it's a pain in the ass... compared to normal remapping.
Here is the normal behaviour of the Numpad8-key:
With numpad on:
num8: up
shift+num8: mark up
With numpad off:
num8: 8
shift+num8:up
So if you want to reverse that, what we want is this:
With numpad on:
num8: 8
shift+num8:up
With numpad off:
num8: up
shift+num8: mark up
This is how it could be achived:
*NumpadUp::
If GetKeyState("NumLock", "T")
SendInput, {Shift Down}{Up}
Else If GetKeyState("Shift")
SendInput, {Shift Up}{NumpadUp}
Else
SendInput, {Shift Up}{Numpad8}
Return
*Numpad8::
If GetKeyState("Shift")
SendInput, {Shift Down}{NumpadUp}
Else
SendInput, {NumpadUp}
Return
Now you just need to do the same thing for the other numpad keys that you want to reverse.
Here is a different approach that uses a little hack to make it look like the Numpad toggles when pressing the numlock key. But it ensures that the numlock actually is always off and only the numlock light is changed.
SetNumLockState, Off
fakeNumlockOn := False
Return
NumLock::
SetNumLockState, Off
fakeNumlockOn := !fakeNumlockOn
SetNumLockLEDs(fakeNumlockOn ? "on" : "off")
Sleep, 100
SetNumLockLEDs(fakeNumlockOn ? "on" : "off")
Return
SetNumLockLEDs(state) {
Loop, 11
KeyboardLED(2,state,A_Index-1)
}
/*
Keyboard LED control for AutoHotkey_L
http://www.autohotkey.com/forum/viewtopic.php?p=468000#468000
KeyboardLED(LEDvalue, "Cmd", Kbd)
LEDvalue - ScrollLock=1, NumLock=2, CapsLock=4
Cmd - on/off/switch
Kbd - index of keyboard (probably 0 or 2)
*/
KeyboardLED(LEDvalue, Cmd, Kbd=0) {
SetUnicodeStr(fn,"\Device\KeyBoardClass" Kbd)
h_device := NtCreateFile(fn,0+0x00000100+0x00000080+0x00100000,1,1,0x00000040+0x00000020,0)
If (Cmd = "switch") ;switches every LED according to LEDvalue
KeyLED:= LEDvalue
If (Cmd = "on") ;forces all choosen LED's to ON (LEDvalue= 0 ->LED's according to keystate)
KeyLED:= LEDvalue | (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
If (Cmd = "off") { ;forces all choosen LED's to OFF (LEDvalue= 0 ->LED's according to keystate)
LEDvalue := LEDvalue ^ 7
KeyLED := LEDvalue & (GetKeyState("ScrollLock", "T") + 2*GetKeyState("NumLock", "T") + 4*GetKeyState("CapsLock", "T"))
}
success := DllCall( "DeviceIoControl" , "ptr", h_device , "uint", CTL_CODE( 0x0000000b , 2 , 0 , 0 ) , "int*", KeyLED << 16 , "uint", 4 , "ptr", 0 , "uint", 0 , "ptr*", output_actual , "ptr", 0 )
NtCloseFile(h_device)
return success
}
CTL_CODE( p_device_type, p_function, p_method, p_access ) {
return, ( p_device_type << 16 ) | ( p_access << 14 ) | ( p_function << 2 ) | p_method
}
NtCreateFile(ByRef wfilename,desiredaccess,sharemode,createdist,flags,fattribs) {
VarSetCapacity(objattrib,6*A_PtrSize,0)
VarSetCapacity(io,2*A_PtrSize,0)
VarSetCapacity(pus,2*A_PtrSize)
DllCall("ntdll\RtlInitUnicodeString","ptr",&pus,"ptr",&wfilename)
NumPut(6*A_PtrSize,objattrib,0)
NumPut(&pus,objattrib,2*A_PtrSize)
status:=DllCall("ntdll\ZwCreateFile","ptr*",fh,"UInt",desiredaccess,"ptr",&objattrib ,"ptr",&io,"ptr",0,"UInt",fattribs,"UInt",sharemode,"UInt",createdist ,"UInt",flags,"ptr",0,"UInt",0, "UInt")
return % fh
}
NtCloseFile(handle) {
return DllCall("ntdll\ZwClose","ptr",handle)
}
SetUnicodeStr(ByRef out, str_) {
VarSetCapacity(out,2*StrPut(str_,"utf-16"))
StrPut(str_,&out,"utf-16")
}

Tooltip on control focus ahk

In Autohotkey, is there a way to detect what gui control has focus so that I display a text box with basically a tooltip.
I want to hover my mouse or use the keyboard to navigate and display what would be stored in the tooltip in a multiline textbox.
I dont want to have a tooltip.
OnMessage(0x0200, "WM_MOUSEMOVE") ; WM_MOUSEMOVE 0x0200
Return
WM_MOUSEMOVE(wParam, lParam)
{
global Control_Name
X := lParam & 0xFFFF
Y := lParam >> 16
MouseGetPos, , , , Control_Name
Tooltip, %Control_Name%, (x+150), (y+150)
}
Esc::ExitApp
ControlGetFocus is used to get the name. See sample code below
a::
ControlGetFocus, OutputVar, A
if ErrorLevel
MsgBox, The target window doesn't exist or none of its controls has input focus.
else
MsgBox, Control with focus = %OutputVar%
Got it! ;-)
I watch if the mouse moves, or a control has focus and display in a text box some stored values
#Persistent
SetTimer, WatchCursor, 100
return
WatchCursor:
MouseGetPos, mx, my, id, mouseControl
ControlGetFocus, currentFocus, A
if (SubStr(mouseControl,1,6)= "Button" OR SubStr(currentFocus,1,6)= "Button")
butIDkey := SubStr(currentFocus,7,2)
butIDmouse := SubStr(mouseControl,7,2)
if (SubStr(mouseControl,1,6)= "Button" && lastmx <> mx && lastmy <> my)
butID := butIDmouse
if (butIDkey <> lastControl)
butID := butIDkey
lastControl := butIDkey
lastmx := mx
lastmy := my
GuiControl,TemplateEngine:, MyTooltip, % Value%butID%
}
return