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
I have very redundant code that I need to simplify as I am expanding and I am not sure how to do this. I have a lot of buttons that get updated and images changed quite often. Depending on what button is lit up and what is going on in the program, I change the state of a lot of buttons at once. I would like to create a function that can iterate multiple parts of the function. . .for example, below is a chunk of code that is repeated 1 time per button that I have, which at this point is going to be 48. . .
if sharedData.Channel1Mute != nil {
if sharedData.Channel1Mute == "True" {
self.Channel1Button.setImage(UIImage(named: "w1"), for:UIControlState())
}
else {
self.Channel1Button.setImage(UIImage(named: "g1"), for:UIControlState())
}
if sharedData.Channel2Mute != nil {
if sharedData.Channel2Mute == "True" {
self.Channel2Button.setImage(UIImage(named: "w2"), for:UIControlState())
}
else {
self.Channel2Button.setImage(UIImage(named: "g2"), for:UIControlState())
}
...
...
ect
...
This isn't correct coding but I would like this to function something like this which would be MUCH shorter and scalable . . .
for NUMBER in 1...48 {
if sharedData.Channel[NUMBER]Mute != nil {
if sharedData.Channel[NUMBER]Mute == "True" {
self.Channel[NUMBER]Button.setImage(UIImage(named: "w[NUMBER]"), for:UIControlState())
}
else {
self.Channel[NUMBER]Button.setImage(UIImage(named: "g[NUMBER]"), for:UIControlState())
}
}
This is frustrating because my current code does the exact same thing like 48 times but I have to rewrite the whole code again with each number in the if statement in each copy.
Searching in files for some code lines. My script for first line:
FileReadLine, OutputVar, C:\Files\prog.txt, 1
If (OutputVar = "FileRead, OutputVar, C:\Files\prog1.txt")
MsgBox Code line found
else
MsgBox Code line not found
How searching by this method in some area? Lines from 50 to 250, 205 to 551, etc.
Use a file parsing loop: http://ahkscript.org/docs/commands/LoopReadFile.htm
Loop, read, C:\Files\prog.txt
{
If (A_LoopReadLine = "FileRead, OutputVar, C:\Files\prog1.txt") {
MsgBox, An interesting code line was found.
} Else If (A_LoopReadLine = "blablabla") {
MsgBox, An interesting code line was found.
} Else If (A_LoopReadLine = "some other text line") {
MsgBox, An interesting code line was found.
;} Else {
; MsgBox, Nothing important was found
;}
}
My Code is below.Whenever I try to run it I get an error saying I'm using duplicate hotkeys when in practice they would never interfere with each other. How do I get around this?
"Your post does not have much context to explain the code sections; please explain your scenario more clearly.". So I guess need to explain my code.. It's extremely simple I have a state variable that is changed by pressing the arrow keys, then I have if statements that checks what the state is. If I press numpad1 when state = "up" the script should type "A", if the state = "right" it would print I. However I'm getting an error since I used the same hotkey multiple times in my different if statements.
state := "none"
UP::
state := "up"
Right::
state := "right"
DOWN::
state := "down"
LEFT::
state := "left"
if (state = "up"){
Numpad1::
Send A
Return
Numpad2::
Send B
Return
Numpad3::
Send C
Return
Numpad4::
Send D
Return
Numpad6::
Send E
Return
Numpad7::
Send F
Return
Numpad8::
Send G
Return
Numpad9::
Send H
Return
}
if (sate = "right"){
Numpad1::
Send I
Return
Numpad2::
Send J
Return
Numpad3::
Send K
Return
Numpad4::
Send L
Return
Numpad6::
Send M
Return
Numpad7::
Send N
Return
Numpad8::
Send O
Return
Numpad9::
Send P
Return
}
if (state = "down"){
Numpad1::
Send Q
Return
Numpad2::
Send R
Return
Numpad3::
Send S
Return
Numpad4::
Send T
Return
Numpad6::
Send U
Return
Numpad7::
Send V
Return
Numpad8::
Send W
Return
Numpad9::
Send X
Return
}
if (state = "left"){
Numpad1::
Send Y
Return
Numpad2::
Send Z
Return
}
When you use AHK_L, you can use #IF with multiple definitions of the same hotkey. WARNING this does NOT work with the regular AHK version.
Here is an example.
You set the variables by typing none\ right\ or left\ .
Depending on the variable setting your Tab key will either send NORMAL, LEFT or RIGHT.
#SingleInstance Force
Tab::Send, NORMAL
#if (state = "left")
Tab::Send, LEFT
#if ; End #if (state = "left")
#if (state = "right")
Tab::Send, RIGHT
#if ; End #if (state = "right")
:*:right\::
state := "right"
Return
:*:left\::
state := "left"
Return
:*:none\::
state := "none"
Return
Alternatively, with the normal AHK, you define ONE hotkey and place IF statements inside the hotkeys to change the behaviour based on the state variable.
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++.