How to make `ifWinActive` and `WinActivateBottom` to use only the current desktop? - autohotkey

I have an autohotkey script that search if specific window exists, if so, it will activate it.
I want that it will search only in the current desktop (I'm using Windows 10).
Do you have a suggestion how to do it?
My Script:
#c::
IfWinExist ,ahk_class ConsoleWindowClass
{
ifWinActive
WinActivatebottom ,ahk_class ConsoleWindowClass
else
WinActivate
return
}

#c:: WinActivateBottomOnCurrentVirtualDesktop("ConsoleWindowClass")
WinActivateBottomOnCurrentVirtualDesktop(Class){
IfWinExist, ahk_class %Class%
{
list := ""
LastWin := ""
; get a list of those windows on the current desktop
WinGet, id, list, ahk_class %Class%
Loop, %id%
{
this_ID := id%A_Index%
If IsWindowOnCurrentVirtualDesktop(this_ID)
LastWin := this_ID ; retrieves the bottommost matching window ID
}
WinActivate, ahk_id %LastWin%
}
}
; https://autohotkey.com/boards/viewtopic.php?p=64295#p64295
; Indicates whether the provided window is on the currently active virtual desktop:
IsWindowOnCurrentVirtualDesktop(hWnd) {
onCurrentDesktop := ""
CLSID := "{aa509086-5ca9-4c25-8f95-589d3c07b48a}"
IID := "{a5cd92ff-29be-454c-8d04-d82879fb3f1b}"
IVirtualDesktopManager := ComObjCreate(CLSID, IID)
Error := DllCall(NumGet(NumGet(IVirtualDesktopManager+0), 3*A_PtrSize), "Ptr", IVirtualDesktopManager, "Ptr", hWnd, "IntP", onCurrentDesktop)
ObjRelease(IVirtualDesktopManager)
if !(Error=0)
return false, ErrorLevel := true
return onCurrentDesktop, ErrorLevel := false
}

Related

Global variable doesn't update until function finishes?

I'm trying to prevent a function (^F1) from being run twice at the same time.
To do this, I'm trying to use a global lock variable; the function needs to release the lock to enable another function call.
Now, this below code would work in Java, but it's not working in AHK. The problem is that, in AHK, the global "is_locked" does not update until ^F1 has finished. This defeats the purpose of using a global lock variable to prevent simultaneous function calls.
How can I fix this?
is_locked := False
set_lock()
{
global is_locked
is_locked := True
}
remove_lock()
{
global is_locked
is_locked := False
}
^F1::
global is_locked
if(is_locked)
{
; doesn't print until after 10 seconds, even if I am spamming ^F1
MsgBox, "locked"
return
}
set_lock()
Sleep 10000
return
Take note that is_locked is a super-global variable.
global is_locked := false
set_lock()
{
is_locked := true
}
remove_lock()
{
is_locked := false
}
^F1::
if (is_locked)
return
set_lock()
MsgBox, "locked"
Sleep 10000
remove_lock()
return
global is_locked
toggle_lock() {
is_locked := !is_locked
OutputDebug, % is_locked
}
^F1::
toggle_lock()
if is_locked
ToolTip, locked
Else
ToolTip, NOT locked
return

FB_FileOpen stays busy, Statemachine not working - TwinCat3

i am trying to get into the beckhoff/twincat universe, therefore is was following along with some twincat tutorials. While programming a simple event-logger I encountered the following problem:
After executing FB_FileOpen, it´s bBusy variable stays True - therefore my statemachine won´t execute any further and is stuck in FILE_OPEN. Any idea, what I did wrong? Here is my code:
VAR
FileOpen : FB_FileOpen := (sPathName := 'C:\Events-log.txt', nMode := FOPEN_MODEAPPEND OR FOPEN_MODETEXT);
FileClose :FB_FileClose;
FilePuts : FB_FilePuts;
stEventWrittenToFile : ST_Event;
CsvString : T_MaxString;
eWriteState :(TRIGGER_FILE_OPEN, FILE_OPEN, WAIT_FOR_EVENT,TRIGGER_WRITE_EVENT, WRITE_EVENT, FILE_CLOSE, ERROR);
END_VAR
CASE eWriteState OF
TRIGGER_FILE_OPEN :
FileOpen(bExecute := TRUE);
eWriteState := FILE_OPEN;
FILE_OPEN :
FileOpen(bExecute := FALSE);
IF FileOpen.bError THEN
eWriteState := ERROR;
ELSIF NOT FileOpen.bBusy AND FileOpen.hFile <> 0 THEN
eWriteState := WAIT_FOR_EVENT;
END_IF
WAIT_FOR_EVENT :
//Do nothing, triggered externally by method
TRIGGER_WRITE_EVENT :
CsvString := ConvertStructureToString(stEvent := stEventWrittenToFile);
FilePuts( sLine:= CsvString,
hFile := FileOpen.hFile,
bExecute := TRUE,);
eWriteState := WRITE_EVENT;
WRITE_EVENT :
FilePuts(bExecute := FALSE);
IF FilePuts.bError THEN
eWriteState := ERROR;
ELSIF NOT FilePuts.bBusy THEN
eWriteState := FILE_CLOSE;
END_IF
FILE_CLOSE :
FileClose( hFile := FileOpen.hFile,
bExecute := TRUE);
IF FileClose.bError = TRUE THEN
FileClose.bExecute := FALSE;
eWriteState := ERROR;
ELSIF NOT FileClose.bBusy THEN
FileClose.bExecute := FALSE;
eWriteState := TRIGGER_FILE_OPEN;
END_IF
ERROR : // Do nothing
END_CASE
The issue probably lies in how you call the function block. You need to make sure to call the function block with the input bExecute := FALSE and only after that calling it with bExecute := TRUE will trigger the function block execution. Caliing the fb with its "exectue" input to false after it has had the input triggered, will always work so just invert your order of TRUE and FALSE executes for all your states.
TRIGGER_FILE_OPEN:
fileOpen(bExecute := FALSE);
eWriteState := FILE_OPEN;
FILE_OPEN:
fileOpen(bExecute := TRUE);
...
You could also follow the Beckhoff example provided on their website, not a fan of this, but calling the function block twice, back to back in a single PLC cycle :
(* Open source file *)
fbFileOpen( bExecute := FALSE );
fbFileOpen( sNetId := sSrcNetId,
sPathName := sSrcPathName,
nMode := FOPEN_MODEREAD OR FOPEN_MODEBINARY,
ePath := PATH_GENERIC,
tTimeout := tTimeOut,
bExecute := TRUE );
Full example can be found here : https://infosys.beckhoff.com/english.php?content=../content/1033/tcplclib_tc2_system/30977547.html&id=
I found the error.
My mistake was, that I started the state machine with a positive edge from a start variable. Since I am running the task in a 1ms cycle, the whole thing would´ve needed to complete within 1ms then.

AHK: StringReplace name into email

I have created a template for send out emails to clients of the new user I have created.
The current code have it to remove the space and add a period. For Example: John Smith will be turned into John.Smith#test.com
StringReplace, UserID, UserID, %A_SPACE%, . , All
I would like to create a script to remove the space and letters up to the first letter creating JSmith#test.com
Here is the current script I have:
InputBox, ClientE, Client Name, Please type the name of Company
if ClientE = test
{
EmailE = test.com
}
if (A_hour >= 12) {
InputBox, UserID, User's Name, Please type the user's name
InputBox, PASSWE, Password, Please type the password
sleep, 700
Send, Good Afternoon ,{Enter 2}This e-mail is to inform you that the requested new user account for{space}
Send, ^b
Send, %UserID%
Send, ^b
Send, {space}has been created as follows;{ENTER 2}
StringReplace, UserID, UserID, %A_SPACE%, . , All
Send, Desktop user name = %UserID% {ENTER}E-mail address = %UserID%#%EmailE%{SPACE} {ENTER}Password = {SPACE}{ENTER 2}Please let me know if you need anything further.{ENTER 2}Best regards,{ENTER 2}Garrett Haggard
}
else
{
InputBox, UserID, User's Name, Please type which user
sleep, 700
Send, Good Morning ,{Enter 2}This e-mail is to inform you that the requested new user account for{space}
Send, ^b
Send, %UserID%
Send, ^b
Send, {space}has been created as follows;{ENTER 2}
StringReplace, UserID, UserID, %A_SPACE%, . , All
Send, Desktop user name =
Send, ^b
Send, %UserID%
Send, ^b
Send, {ENTER}E-mail address = %UserID%#%EmailE%{SPACE} {ENTER}Password =
Send, ^b
Send, %PASSWE%
Send, ^b
Send, {SPACE}{ENTER 2}Please let me know if you need anything further.{ENTER 2}Best regards,{ENTER 2}
}
return
UserID := "John Smith"
stringSplit, user_first_last, UserID, %A_Space%
StringLeft, first_initial, user_first_last1, 1
email := first_initial . user_first_last2 . "#test.com"
msgbox, %email%
return
Here is the code with the updated/additional scrit
{
if (A_hour >=12)
{
RTYH = Good Afternoon
}
Else
{
RTYH = Good Morning
}
InputBox, ClientE, Client Name, Please type the name of Company
InputBox, UserID, User's Name, Please type the user's name
;InputBox, PASSWE, Password, Please type the password
sleep, 700
Send, %RTYH% ,{Enter 2}This e-mail is to inform you that the requested new user account for{space}
Send, ^b
Send, %UserID%
Send, ^b
Send, {space}has been created as follows;{ENTER 2}
if ClientE = test
{
UserID := UserID
stringSplit, user_first_last, UserID, %A_Space%
StringLeft, first_initial, user_first_last1, 1
UserID4 := first_initial . user_first_last2
UserID5 := first_initial . user_first_last2 . "#test.com"
}
if ClientE = testing
{
UserID := UserID
stringSplit, user_first_last, UserID, %A_Space%
StringReplace, UserID4, UserID, %A_SPACE%, . , All
UserID4 := UserID4
UserID5 := UserID4 . "#testing.com"
}
Send, Desktop user name =
Send, ^b
Send, %UserID4%
Send, ^b
Send, {ENTER}E-mail address = %UserID5%{SPACE} {ENTER}Password ={SPACE}{ENTER 2}Please let me know if you need anything further.{ENTER 2}Best regards,{ENTER 2}
}
return

autohotkey flags keeps skipping my function

can you guys help me, i have added a flag, however it skips teleport() and keeps walksouth() any idea why? I'm kinda newbie here i hope you guys help me
walk1 := 0
loop {
teleport()
}
teleport()
{
if (walk1 => 1) ;this never worked even i added flag walk1:=1 :( please help
send, {f9}
sleep, 500
walk1 := 0
return
} else if (walk1 <= 0){
walksouth()
return
}
}
walksouth() { ;this keeps running and skipping teleport()
send, {f5}
sleep, 500
walk1 := 1 ;added flag 1 to run the teleport, but still skipping
return
}
This is your corrected and refactored code:
walk := false
loop {
teleport()
}
teleport()
{
global walk
if (walk) {
send {f9}
walk := false
} else {
send {f5}
walk := true
}
sleep 500
}
Bugs in your code:
Variables in functions have local scope unless they are declare using global. So the walk1 variables in your functions and the global walk1 are all different variables
You are missing an open brace { after if (walk1 => 1)

Disable JavaScript in Webbrowser Control in AutoHotkey

I thought even after rendering the page, removing script tags and the relevant attributes in tags would work but didn't.
The following code removes the script tag and the onclick attribute but it does not have any effect.
Any idea?
I'd like to avoid:
editing the registroy since it requires admin rights.
fetching web contents separately and using doc.write() since it make the code complex.
Files:
javascript.html
test.ahk
javascript.html
<!DOCTYPE html>
<html>
<head>
<script> function displayDate() { document.getElementById("demo").innerHTML=Date(); }</script>
</head>
<body>
<p id="demo" onclick="displayDate()">This is a paragraph. Click here.</p>
</body>
</html>
test.ahk
Gui, Add, ActiveX, vWB w400 h300, Shell.Explorer
Gui, Show, w420 h320
WB.Navigate("file:///" A_ScriptDir "/javascript.html")
Loop
Sleep 10
Until (WB.readyState=4 && WB.document.readyState="complete" && !WB.busy)
doc := WB.document
nodeScript := doc.getElementsByTagName("script")[0]
nodeScript.parentNode.removeChild(nodeScript)
nodeP := doc.getElementsByTagName("p")[0]
nodeP.removeAttribute("onclick")
msgbox % doc.documentElement.outerHTML
Return
It is possible to force scripting enabled/disabled for a given WebBrowser control by implementing three specific COM interfaces (IOleClientSite, IServiceProvider and IInternetSecurityManager) and calling the SetClientSite method of the control's IOleObject interface.
Ultimately, you need to implement the IInternetSecurityManager::ProcessUrlAction method. When the WebBrowser calls it with the dwAction parameter set to URLACTION_SCRIPT_RUN, you can set *pPolicy to URLPOLICY_DISALLOW to prevent scripting or URLPOLICY_ALLOW to enable scripting, and return S_OK (zero) to enforce the policy.
The necessary code is shown below, and can be implemented by simply calling SetWBClientSite() after creating the control but before navigating. The global variable WB must contain a reference to the WebBrowser control.
/* Complex workaround to override "Active scripting" setting
* and ensure scripts can't run within the WebBrowser control.
*/
global WBClientSite
SetWBClientSite()
{
interfaces := {
(Join,
IOleClientSite: [0,3,1,0,1,0]
IServiceProvider: [3]
IInternetSecurityManager: [1,1,3,4,8,7,3,3]
)}
unkQI := RegisterCallback("WBClientSite_QI", "Fast")
unkAddRef := RegisterCallback("WBClientSite_AddRef", "Fast")
unkRelease := RegisterCallback("WBClientSite_Release", "Fast")
WBClientSite := {_buffers: bufs := {}}, bufn := 0,
for name, prms in interfaces
{
bufn += 1
bufs.SetCapacity(bufn, (4 + prms.MaxIndex()) * A_PtrSize)
buf := bufs.GetAddress(bufn)
NumPut(unkQI, buf + 1*A_PtrSize)
NumPut(unkAddRef, buf + 2*A_PtrSize)
NumPut(unkRelease, buf + 3*A_PtrSize)
for i, prmc in prms
NumPut(RegisterCallback("WBClientSite_" name, "Fast", prmc+1, i), buf + (3+i)*A_PtrSize)
NumPut(buf + A_PtrSize, buf + 0)
WBClientSite[name] := buf
}
global wb
if pOleObject := ComObjQuery(wb, "{00000112-0000-0000-C000-000000000046}")
{ ; IOleObject::SetClientSite
DllCall(NumGet(NumGet(pOleObject+0)+3*A_PtrSize), "ptr"
, pOleObject, "ptr", WBClientSite.IOleClientSite, "uint")
ObjRelease(pOleObject)
}
}
WBClientSite_QI(p, piid, ppvObject)
{
static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
static IID_IOleClientSite := "{00000118-0000-0000-C000-000000000046}"
static IID_IServiceProvider := "{6d5140c1-7436-11ce-8034-00aa006009fa}"
iid := _String4GUID(piid)
if (iid = IID_IOleClientSite || iid = IID_IUnknown)
{
NumPut(WBClientSite.IOleClientSite, ppvObject+0)
return 0 ; S_OK
}
if (iid = IID_IServiceProvider)
{
NumPut(WBClientSite.IServiceProvider, ppvObject+0)
return 0 ; S_OK
}
NumPut(0, ppvObject+0)
return 0x80004002 ; E_NOINTERFACE
}
WBClientSite_AddRef(p)
{
return 1
}
WBClientSite_Release(p)
{
return 1
}
WBClientSite_IOleClientSite(p, p1="", p2="", p3="")
{
if (A_EventInfo = 3) ; GetContainer
{
NumPut(0, p1+0) ; *ppContainer := NULL
return 0x80004002 ; E_NOINTERFACE
}
return 0x80004001 ; E_NOTIMPL
}
WBClientSite_IServiceProvider(p, pguidService, piid, ppvObject)
{
static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
static IID_IInternetSecurityManager := "{79eac9ee-baf9-11ce-8c82-00aa004ba90b}"
if (_String4GUID(pguidService) = IID_IInternetSecurityManager)
{
iid := _String4GUID(piid)
if (iid = IID_IInternetSecurityManager || iid = IID_IUnknown)
{
NumPut(WBClientSite.IInternetSecurityManager, ppvObject+0)
return 0 ; S_OK
}
NumPut(0, ppvObject+0)
return 0x80004002 ; E_NOINTERFACE
}
NumPut(0, ppvObject+0)
return 0x80004001 ; E_NOTIMPL
}
WBClientSite_IInternetSecurityManager(p, p1="", p2="", p3="", p4="", p5="", p6="", p7="", p8="")
{
if (A_EventInfo = 5) ; ProcessUrlAction
{
if (p2 = 0x1400) ; dwAction = URLACTION_SCRIPT_RUN
{
NumPut((URLPOLICY_DISALLOW := 3), p3+0) ; *pPolicy := URLPOLICY_DISALLOW
return 0 ; S_OK
}
}
return 0x800C0011 ; INET_E_DEFAULT_ACTION
}
_String4GUID(pGUID)
{
VarSetCapacity(String,38*2)
DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
Return String
}
The current AutoHotkey installer contains code identical to this, with the exception that it sets URLPOLICY_ALLOW (0) rather than URLPOLICY_DISALLOW (3). This was necessary to allow the installer to work on systems which have scripting disabled.
As you can see, implementing COM interfaces directly in an AutoHotkey script is no simple matter. It is a little easier in plain C (see COM in plain C), and much easier in C++.