I want my function to be able to set CoordMode as it wants but then return it to the state it was in when the function was called. According to the thread linked below, the answer seems to be to make the function a separate thread so that it doesn't change the CoordMode of the thread that called it.
http://www.autohotkey.com/board/topic/6 ... e-setting/
Since it is now several years later, perhaps there is a way to identify the current CoordMode settings so they can be changed back, but I am not able to find it. Does anyone know how to get this info?
Return CoordMode to its prior state
Re: Return CoordMode to its prior state
You can use Bind() to start function in new thread via SetTimer:
Code: Select all
Gui,Show,w100 h100,Test
fn:=Func("fun").Bind()
SetTimer,% fn, -100
Sleep 3000
ToolTip Test,0,0
return
GuiClose:
ExitApp
fun(){
CoordMode,ToolTip,Screen
ToolTip Hello,0,0
}
Re: Return CoordMode to its prior state
Thanks. If this function is to be a library function (rather than explicitly #Included), then does AHK only include the function itself rather than any associated commands, such as the Bind() and SetTimer lines that are in that file? If that's the case, will this approach not work for library functions unless the calling script adds those lines itself?
Re: Return CoordMode to its prior state
Correct, you would need to #include the function.
Btw. in AHK_H you can use A_CoordModeTooltip to restore previous value:
Btw. in AHK_H you can use A_CoordModeTooltip to restore previous value:
Code: Select all
fun(){
prev:=A_CoordModeToolTip
CoordMode,ToolTip,Screen
ToolTip Hello,0,0
CoordMode,ToolTip,% prev
}
Re: Return CoordMode to its prior state
No, not correct.
AutoHotkey includes the whole file, not just the function. I would have expected HotKeyIt to know that.
However, auto-includes are included after the implicit "Exit" which exists at the end of the main script, so they are never part of the auto-execute section.
Note also that timers aren't guaranteed to be able to run. You might need to change the current thread settings, which would defeat the purpose. You can use a callback (RegisterCallback + DllCall) instead.Usage notes:
There are probably any number of ways that you could make it more self-contained or more convenient. Here's a random experiment:
The function just needs to contain the first two lines, which redirect to a new thread. It must use .r for the actual return value; I returned the prm object because objects are always boolean true. Originally I intended to use a ByRef parameter for the result, but callbacks don't support functions which have ByRef parameters.
Exception() is used to determine the name of the function which called CallSelf' and whether that function was called by CallSelf' (i.e. it's running in a new thread). This will not work if the script is compiled.
AutoHotkey includes the whole file, not just the function. I would have expected HotKeyIt to know that.
However, auto-includes are included after the implicit "Exit" which exists at the end of the main script, so they are never part of the auto-execute section.
Note also that timers aren't guaranteed to be able to run. You might need to change the current thread settings, which would defeat the purpose. You can use a callback (RegisterCallback + DllCall) instead.
Code: Select all
Critical ; These would prevent timers from running,
Thread NoTimers ; but not callbacks.
MsgBox % CallInNewThread("MyFn", "Hello, world!")
. "`nTTM is " A_TitleMatchMode
MyFn(a) {
SetTitleMatchMode RegEx
MsgBox %a%`nTTM is %A_TitleMatchMode%
return 42
}
CallInNewThread(fn, prm*) {
if (!IsObject(prm))
return 0, prm := Object(fn), prm.r := prm.fn.Call(prm*)
static cb := 0
prm.fn := IsObject(fn) ? fn : Func(fn)
DllCall((cb ? cb : cb := RegisterCallback(A_ThisFunc, "", 1)), "ptr", &prm)
return prm.r
}
- You can pass any number of parameters and pass or return any type of value, but ByRef is not supported.
- Callbacks require a real script function, so fn must be a name or Func object.
- prm is the address of the parameters when called by a callback, or an array of parameters in any other case.
- Callbacks can only pass and return integers, so the parameter array object is passed by address and also used to return the result.
- Only one machine code callback is needed for any number of calls, so it is never freed.
There are probably any number of ways that you could make it more self-contained or more convenient. Here's a random experiment:
Code: Select all
MsgBox % MyFn("Hello, world!")
. "`nTTM is " A_TitleMatchMode
MyFn(a) {
if r := CallSelfInNewThread(a)
return r.r
SetTitleMatchMode RegEx
MsgBox %a%`nTTM is %A_TitleMatchMode%
return 42
}
CallSelfInNewThread(prm*) {
if (!IsObject(prm))
return 0, prm := Object(NumGet(prm+0)), prm.r := prm.fn.Call(prm*)
if (Exception("", -3).What = A_ThisFunc)
return false
static cb := 0
prm.fn := Func(Exception("", -2).What)
DllCall((cb ? cb : cb := RegisterCallback(A_ThisFunc, "", 1)), "ptr", &prm)
return prm
}
Exception() is used to determine the name of the function which called CallSelf' and whether that function was called by CallSelf' (i.e. it's running in a new thread). This will not work if the script is compiled.
Re: Return CoordMode to its prior state
Thanks very much for the detailed information.