I am trying to send a keystroke to OBS Studio using AutoHotkey.
The code I am using is
DetectHiddenWindows, On
hWnd := WinExist("ahk_exe obs64.exe")
ControlSend,, {F5}, ahk_id %hWnd%
The function I want to trigger is "start recording"
Nothing is delivered. There is a rumour that the latest OBS does not allow for ControlSend. Is that true? How do I circumvent that?
Use SetKeyDelay (or separate up & down events with delay in between) to make the key be held down for a bit longer.
;hold down for 50ms
SetKeyDelay, -1, 50
ControlSend, , {F5}, ahk_exe obs64.exe
Also, assuming you don't need the hwnd for something else, there's no need to get it.
And it should work just fine as well without detecting hidden windows.
Related
I'm pretty new to ahk.
Say I have two separate vlc windows open and playing videos.
If one of the vlc windows is active, then I want to be able to hold a key to make all keypresses go to the other vlc window.
ie if I press Left, then it sends Left to the active vlc window, but if I hold ALT+Left, then it sends Left to the other vlc window.
If no vlc window is active, then I don't want autohotkey to do anything.
This is so I can control two vlc windows without having to click and choose which one is active.
I looked up GroupAdd hoping I could use a group that includes both vlc windows, but couldn't find a way to target specific vlc windows from the group to send keys to it.
edit: I got a very basic version working, but I feel it's pretty ugly. I would like a way to send any key that's pressed if you hold Shift to the other vlc window. Also this seems a bit unreliable in switching focus if you use it a few times quickly in succession.
GroupAdd, vlcgroup, ahk_exe vlc.exe
return
#IfWinActive ahk_exe vlc.exe
+Left:: ; shift-left
GroupActivate, vlcgroup, r
Send {Left}
GroupActivate, vlcgroup, r
return
A simple approach could be done like this:
#IfWinActive, ahk_exe vlc.exe
+Left::
WinGet, WindowList, List, ahk_exe vlc.exe
BottomMostVlcHwnd := WindowList%WindowList%
ControlSend, , {Left}, % "ahk_id " BottomMostVlcHwnd
return
^+Left::
WinGet, WindowList, List, ahk_exe vlc.exe
BottomMostVlcHwnd := WindowList%WindowList%
ControlSend, , ^{Left}, % "ahk_id " BottomMostVlcHwnd
return
...
#IfWinActive
You'd write out each hotkey.
WinGet, , List(docs) returns a legacy pseudo-array(docs) of hwnds to Vlc windows.
The last element in that array will be the bottom most window.
You can get the last element of a pseudo array via a dynamic variable trick WindowList%WindowList%.
Essentially you're accessing a variable named WindowListN, where N is the number for the last element in the pseudo-array.
Then ControlSend(docs) is used to send keys to the background window without the need to activate it.
And you refer to the background window by a window name like ahk_id 0x1234567(docs).
Of course writing out the hotkey for each key is pretty repetitive, so we can do something much better:
#IfWinActive, ahk_exe vlc.exe
+Left::
^+Left::
+Right::
^+Right::
+PgUp::
+PgDn::
WinGet, WindowList, List, ahk_exe vlc.exe
ControlSend, , % StrReplace(A_ThisHotkey, "+", "{") "}", % "ahk_id " WindowList%WindowList%
return
#IfWinActive
The hotkey definitions are just stacked on top of each other.
(If there were even more definitions, a loop with the Hotkey(docs) command could be nicer)
A_ThisHotkey(docs) will contain the hotkey that was used, and StrReplace(docs) is used to automatically replace the + with a {.
And finally the closing brace } is appended to the end.
I try to send [Strg]+[Win]+[Numpad3] to OBS Studio to pause recording via an Autohotkey script.
My current approach is the following one because I want to avoid that other applications react on this shortcut. For example Notepad++ changes with this the open tabs.
ControlSend, , ^#{Numpad3}, ahk_class Qt5QWindowIcon
Actually, nothing happens in OBS Studio. Even when using {Ctrl down} and {LWin down} it does not work. Do you have an idea?
Use SetKeyDelay (or use separate up & down events with delay inbetween) to make the key be hold down for a bit longer.
Worked for me.
;hold down for 50ms
SetKeyDelay, -1, 50
ControlSend, , ^#{Numpad3}, ahk_class Qt5QWindowIcon
Here is what I'm trying to do and would greatly appreciate any help here.
I am trying to automate maximizing the live conversation window in skype with an Autohotkey script. I'm trying to make it so I can call into a remote machine using skype and have it auto answer (this is native in skype)...once I have a live conversation window I would like to maximize the live conversation window to fill the screen.
I've given this a shot but somehow don't think that I have the correct ahk_class for the live conversation window but there may be something else I am missing. I've placed a the code I've tried using below...any help would be great.
#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.
#Persistent
IfWinExist, TLiveConversationWindow ;
{
WinActivate
WinMaximize
send !{Enter};When using skype normally this Alt+Enter will maximize the window
return
}
I also tried to use this code to determine the proper class for the live conversation window...but has not helped as of yet.
Alt & Enter::
IfWinExist, TLiveConversationWindow
WinActivate
ControlFocus, ClassNN TLiveConversation1
ControlClick, ClassNN TLiveConversation1, , , , 2,
MouseClick, left, , , 2
send !{Enter}
; now we get the ID & CLASS
WinGet, Active_Window_ID, ID, A
WinGetClass, Active_Window_Class, A
MsgBox, The active window's class is "%Active_Window_class%" and ID is %Active_Window_ID%
Was able to get a simplified version of the code to work with a hotkey to initiate but have not been able to get the WinWait function to work as per #Schneyer.
Functioning Code activated by hotkey
#NoEnv
#Warn
#Persistent
SendMode Input
SetWorkingDir %A_ScriptDir%
; Skype Maximizer initiating functions
^!p::
;WinWait ahk_class TLiveConversation1
;WinWait ahk_class TConversationForm
;WinWait ahk_class TLiveConversationWindow
;WinMaximize ahk_class TLiveConversation1
;functioning code
;Activate tSkMainForm.
WinActivate ahk_class tSkMainForm
;Send Alt Enter Input to maximize.
SendInput !{Enter}
;TLiveConversationWindow Always On Top
WinSet, AlwaysOnTop,,ahk_class TLiveConversationWindow
;Minimize main form
WinMinimize ahk_class tSkMainForm
Return
When swapping the ^!p:: with any of the WinWait Functions nothing seems to happen. The WinWait seems like it should be the proper method, any thoughts on why it won't work?
Problems
#persistent lets the script run, but your code still gets executed only once when you start the script. After that it stays active but does nothing.
Use a WinWait to wait for the window to appear (wrap it in a Loop if you want it to run more than once).
Use ahk_class to to search for a window class instead of the window title
Working code
You can use the Window Spy tool which is included in AHK. Use the tray icon menu of a running AHK script to start it.
I use TConversationForm in the code, but it works with every window class.
#NoEnv
#Warn
SendMode Input
SetWorkingDir %A_ScriptDir%
WinWait ahk_class TConversationForm
WinActivate
WinMaximize
Scanning through AHK forums I was able to find a post that led me to the answer for this little problem. Check the below link for further information.
https://autohotkey.com/board/topic/96491-detect-when-a-classnn-window-exists/
The problem with using ahk_class to identify when a skype call was active is that the "active call window" identified as classNN TLiveConversation1 in the inspector was actually a Control within the window of ahk_class tSkMainForm rather than a Window. This made the WinWait function ineffective at identifying it when the call initiated.
In order to identify the Control it is necessary to loop through the controls (using WinGet) in ahk_class tSkMainForm until the TLiveConversation exists and then kick off any subroutines needed. For me that was to maximize the live conversation window.
You'll see the code to do this starting with the WinGet function. All of this is wrapped in a while loop so that it will run persistently allowing it to be called over and over. In essence this code will do the following:
Create a list (SkypeControlList) of controls existing in ahk_class tSkMainForm.
Continually Loop Through SkypeControlList
When a new Live Conversation is initiated a control TLiveConversation1 will exist
Once TLiveConversation1 esists run necessary code
#NoEnv
#Warn
#Persistent
SendMode Event
SetWorkingDir %A_ScriptDir%
DetectHiddenWindows, on
stop = 0
Loop
{
While stop = 0
{
WinGet, SkypeControlList, ControlList, ahk_class tSkMainForm
Loop, Parse,SkypeControlList, `n
{
;Loop to search for control TLiveConversation1
if (A_LoopField = "TLiveConversation1")
{
;Deactivate active screensaver
PostMessage, 0x0112, 0x0F060, 0,, A
;RegWrite REG_SZ, HKEY_CURRENT_USER, Control Panel\Desktop, ScreenSaveActive, 0
;SetKeyDelay, 500
Send {Esc}
;Activate tSkMainForm.
WinActivate ahk_class tSkMainForm
;Send Alt Enter Input to maximize.
Send !{Enter}
;TLiveConversationWindow Always On Top
WinSet, AlwaysOnTop,,ahk_class TLiveConversationWindow
stop = 1
sleep, 100
}
}
}
IfWinExist ahk_class TLiveConversationWindow
{
stop = 1
sleep, 1000
}
IfWinNotExist ahk_class TLiveConversationWindow
{
;Minimize all windows by win+D show desktop
send #d
sleep,1000
; is that call quality feedback window up? kill it.
SetTitleMatchMode, Regex
WinClose, ^Skype.*Call quality feedback$
stop = 0
}
sleep 1000
}
Return
The above code works great as long as there is no screen saver active on the machine being called. If there is an active screen saver the call will answer but the screen saver will not go away. You can see remnants of code trying to wake the computer from a screen saver (This does not currently work).
I've also added a few bits of code to clean up the experience such as removing the call quality popup window that skype throws up after a call as well as clearing the desktop after the call ends.
Thanks to #Blauhirn and #Schneyer for their input in trying to get this solved.
Skype HotKeys are really annoying as they cannot be disabled from Skype itself. The most annoying of all was Ctrl+R, that started a Skype call with any of your contact if it was selected. This has been replaced recently by Ctrl+Alt+R.
See http://community.skype.com/t5/Windows-desktop-client/Disable-CTRL-R-on-windows/td-p/2877763
Unfortunately, it happens to me that I get AltGr+R as a mapped key to the "è" character (using microsoft keybord creator). So in all my applications, I can write happily in French with a US keyboard, using AltGr+r for my "è" character all the time. Except in Skype, now.
Reading the link above, I created an AutoKey script, to disable Skype's hotkey:
#IfWinActive, ahk_exe Skype.exe ; utilizes this script for Skype only
!^r:: ; replace [ctrl][alt][r] with nothing
#If ; closes IfWinActive condition, needed if more code comes after this
But, although this disables the Skype hotkey, it prevents the normal input of my "è" character in a Skype discussion. So good, but not best, as my typing get all mangled in Skype now.
I have tried other options, but to no avail:
#IfWinActive, ahk_exe Skype.exe ; utilizes this script for Skype only
!^r::
Send è
return
#If ; closes IfWinActive condition, needed if more code comes after this
or
#IfWinActive, ahk_exe Skype.exe ; utilizes this script for Skype only
!^r::
SendInput {Raw}è
return
#If ; closes IfWinActive condition, needed if more code comes after this
But as soon as !^r is not strictly disabled, then it launched a Skype call.
Anyone with more experience with AutoHotKey and/or Skype to help me ?
Thanks.
You can avoid the whole problem if you assign the "unfortunate" hotkey combination to something else.
What I did:
Go to Tools->Options->Advanced->Hotkeys
Turn on "Enable keyboard shortcuts"
assign ctrl + alt + r to "Take a snapshot during video calls"
It was driving me crazy, I found the combined answer on skype forums.
Please note that this
#IfWinActive, ...
!^r::
#If
is no valid deactivation of a hotkey: attach the return keyword, so it is !^r::return. Otherwise, after pressing alt ctrl r, any code further down below will also be executed.
Also, if you only want to remap the AltGr hotkey, you should use <^>!r:: as the trigger, as suggested in the documentation. This way, the natural alt+ctrl+r behavior will be preserved, in this case making a call.
I cannot fully reproduce your issue.
#IfWinActive, ahk_exe Skype.exe
<^>!r::
send a
return
#ifWinActive
works perfectly fine for me and does not call my active contact in skype. AltGr is being overridden correctly. But if I change send a to send è, the script starts acting weirdly. It only works for the first time: after that, I have to press Alt manually once in order for è to be sent again. This looks like a bug to me.
A workaround might be
#IfWinActive, ahk_exe Skype.exe
<^>!r::
send è
keywait, alt
send {alt}
return
#ifWinActive
or
#IfWinActive, ahk_exe Skype.exe
<^>!r::
keywait, alt
send è
return
#ifWinActive
. But this still does not make it possible to send multiple è's while holding altGr down. You'll have to release AltGr after each è.
Edit - I found a 100% working solution:
#IfWinActive, ahk_exe Skype.exe
<^>!r::
SendUnicodeChar(0x00E8)
return
#ifWinActive
; SOURCE for the following: http://www.autohotkey.com/board/topic/16404-inserting-unicode-special-characters/
SendUnicodeChar(charCode)
{
VarSetCapacity(ki, 28 * 2, 0)
EncodeInteger(&ki + 0, 1)
EncodeInteger(&ki + 6, charCode)
EncodeInteger(&ki + 8, 4)
EncodeInteger(&ki +28, 1)
EncodeInteger(&ki +34, charCode)
EncodeInteger(&ki +36, 4|2)
DllCall("SendInput", "UInt", 2, "UInt", &ki, "Int", 28)
}
EncodeInteger(ref, val)
{
DllCall("ntdll\RtlFillMemoryUlong", "Uint", ref, "Uint", 4, "Uint", val)
}
this is the same as above, but instead of using send è or send {ASC 0232}, it uses unicode formatting.
The following AHK script automatically brings up the menu that you would normally get when you right-click on the uTorrent icon in the system task-bar tray:
DetectHiddenWindows, On
Process, Exist, utorrent.exe
WinGet, W, List, ahk_pid %ErrorLevel%
Loop %W%
{
WinGetClass, Class, % "ahk_id" W%A_Index%
If InStr( Class, "µTorrent" ) {
hWnd := W%A_Index%
Break
}}
PostMessage, 0x8001, 0,0x204,, ahk_id %hWnd% ; Right Click down
PostMessage, 0x8001, 0,0x205,, ahk_id %hWnd% ; Right Click Up
I understand most of it except the last two lines. 0x8001 is WM_APP+1. Why is a message in the WM_APP range used, and what exactly happens when these two messages are issued? Many thanks for the explanation.
According to MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx#system_defined)
If your application is marked version 4.0, you can use message-identifier values in the range 0x8000 (WM_APP) through 0xBFFF for private messages.
So this would indicate that 0x8001 is an identifier that utorrent has chosen for a message. The 0x204 and 0x205 values are for the Right-Click Down and Up events respectively. My guess is that this code is intended to simulate a Right-Click on utorrent's icon in the Windows tray.
Also, if you're using Autohotkey_L the code can probably be simplified to three lines and perform the same:
DetectHiddenWindows, On
PostMessage, 0x8001, 0,0x204,, ahk_exe utorrent.exe ahk_class µTorrent ; Right Click down
PostMessage, 0x8001, 0,0x205,, ahk_exe utorrent.exe ahk_class µTorrent ; Right Click Up
When you right click on something, the context menu is shown. The context menu can also be shown by pressing the appskey button on the keyboard. When you press it, Windows sends the application a message, i.e., the WM_APP message. Most applications respond by showing a context menu. In the case of the tray icon, the response is the same as the response to a right-click.
Seems that the WM_APP+1 message number is a choice made in the development of the application, in this case utorrent. Could have been another message #, nothing magic. I believe the code I presented (which is from the AHK forums) figured out the message to send through reverse engineering.