I thought the following code may work but did not. The reason probably lies in the fact that the Throw command is executed in the hotkey thread, not in the auto-execution section thread.
try
{
count := 0
loop {
tooltip % ++count
sleep 200
}
} catch {
}
msgbox done
Exitapp
Esc::ExitAPp
^1::throw
So is there a way to know to which thread the flow of control belongs? Does AutoHotkey have a variable for thread IDs or something similar to it?
The below code shows that the both (pseudo) threads return the same number. So I need to know the thread IDs within AutoHotkey if there are. I've read somewhere that an AutoHotkey thread is merely a function call. But I'm expecting that there might be a way to identify the pseudo threads.
try
{
count := 0
loop {
tooltip % ++count "`nThread ID: " DllCall("GetWindowThreadProcessId", "Int", A_ScriptHwnd, "Int", "0")
sleep 200
}
} catch {
}
msgbox done
Exitapp
Esc::ExitAPp
^1::
MsgBox, % DllCall("GetWindowThreadProcessId", "Int", A_ScriptHwnd, "Int", "0")
throw
Return
Is this what you are looking for?
^w::
WinGet, WinID,, A
ThreadID:=DllCall("GetWindowThreadProcessId", "Int", WinID, "Int", "0")
MsgBox, %ThreadID%
Return
Related
I want to bind 'jj' to Esc using AutoHotkey in my Rstudio application. Is there any way we can map 'jj' to trigger Escape in a selected windows application?
I found a solution, that worked.
#IfWinActive ahk_exe rstudio.exe
l::
{
count++
settimer, actions, 150
}
return
actions:
{
if (count = 1)
{
Send j
}
else if (count = 2)
{
Send {Esc}
}
count := 0
}
return
I have a main thread that fires off several other threads to complete various items of work based on what the user choose from the main UI. Normally I'd use WaitForMultipleObjects() with bWaitAll set to TRUE. However, in this case those other threads will log output to another window that uses a mutex to ensure the threads only output one at a time. Part of that process uses SendMessage() to send get the text size and send the text to the windows which will hang if using WaitForMultipleObjects() since it's running from the main UI thread. So I moved over to use MsgWaitForMultipleObjects with QS_SENDMESSAGE flag, only it's problem is the logic for bWaitAll which states it will only return if all objects are signaled AND an input event occurred (instead of returning when all objects are signaled OR an input event occurred). Had the logic been OR this should have worked:
DWORD waitres=WAIT_FAILED;
while (1)
{
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
// mfc message pump
if (!theApp.PumpMessage()) {
// program end request
// TO DO
}
}
// MFC idel processing
LONG lidlecount = 0;
while (theApp.OnIdle(lidlecount++));
// our wait
waitres = ::MsgWaitForMultipleObjects(threadcount, threadhandles, TRUE, INFINITE, QS_SENDMESSAGE);
// check if ended due to message
if (waitres!=WAIT_OBJECT_0+threadcount) {
// no, exit loop
break;
}
}
Rather than fire off a thread that then fires off the other threads I wondered what is the correct way to handle this from the main thread? I thought about using bWaitAll FALSE then using WaitForMultipleObjects() with bWaitAll set to TRUE and the dwMilliseconds set to 0 (or 1) and checking the result to see if completed. If not, it would need to loop back to the top of the loop and then to MsgWaitForMultipleObjects() which when using bWaitAll FALSE could return right away if one of the many threads completed (say 1 thread of 10 completed, I could check as mentioned above if all completed, but when going back with bWaitAll FALSE it will just return and not wait).
So what is the proper way to handle waiting for multiple threads (that use SendMessage()) to complete in the main thread of an MFC application?
Thanks.
So what is the proper way to handle waiting for multiple threads to
complete
need create some structure, with reference count and pass pointer to this structure to every thread. here also probably exist sense have some common task data. and HWND of some window in main(GUI) thread. when worked thread exit - it release reference on object. when last thread exit - delete object and post some message to window, from main thread.
so we not need store thread handles (can just close it) and wait om multiple handles. instead we got some window message when all thread finish task
example of code
struct Task
{
HWND _hwnd;
LONG _dwRefCount = 1;
// some common task data probably ..
Task(HWND hwnd) : _hwnd(hwnd) {}
~Task() {
PostMessageW(_hwnd, WM_USER, 0, 0);// WM_USER as demo only
}
void AddRef(){
InterlockedIncrementNoFence(&_dwRefCount);
}
void Release(){
if (!InterlockedDecrement(&_dwRefCount)) delete this;
}
};
ULONG CALLBACK WorkThread(void* pTask)
{
WCHAR sz[16];
swprintf_s(sz, _countof(sz), L"%x", GetCurrentThreadId());
MessageBoxW(0, L"working...", sz, MB_ICONINFORMATION|MB_OK);
reinterpret_cast<Task*>(pTask)->Release();
return 0;
}
void StartTask(HWND hwnd, ULONG n)
{
if (Task* pTask = new Task(hwnd))
{
do
{
pTask->AddRef();
if (HANDLE hThread = CreateThread(0, 0, WorkThread, pTask, 0, 0))
{
CloseHandle(hThread);
}
else
{
pTask->Release();
}
} while (--n);
pTask->Release();
}
}
It is supposed to put an entry in a text file each time a new window is active, instead it constantly loops and puts thousands of entries while the window is active, if anyone is capable of rectifying this I would be grateful.
loop
{
if new_window = %window_title%
new_window = diff
else
{
WinGetActiveTitle, window_title
fileappend, %window_title%`n, C:\mydirectory\myname.txt
new_window = %window_title%
}
}
Any help able to be provided would be more than welcome.
This uses a timer to check for a new window every 0.5 seconds.
#Persistent
prev_window := ""
settimer, check_window, 500
return
check_window:
WinGetActiveTitle, active_window
if (active_window != prev_window) {
fileappend, %active_window%`n, myname.txt
prev_window := active_window
}
return
The same could be accomplished in a loop:
prev_window := ""
loop
{
WinGetActiveTitle, active_window
if (active_window != prev_window) {
fileappend, %active_window%`n, myname.txt
prev_window := active_window
}
sleep, 500
}
return
You should probably put a SetTimer that checks active window title in some time interval (100ms or something) and compare to previously checked window tile - and if it has changed then write to file.
On Windows 10, I'm waiting for input from the console using
WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), ... )
and to cancel this waiting using CancelSynchronousIo().
But the cancellation does nothing (returns 0 and GetLastError() is ERROR_NOT_FOUND).
Any idea what I could be doing wrong?
Should I be able to cancel this waiting for new input on stdin?
(I actually want to do this with any HANDLE whose GetFileType() is FILE_TYPE_CHAR, not only stdin, but stdin is certainly the most important use case and the simplest to test with).
Related discussions I've found:
Synchronous ReadFile() on stdin cannot be unblocked by CancelSynchronousIo()
win32: how stop ReadFile (stdin|pipe)
But unfortunately they only discuss ReadFile(), not WaitForSingleObject(). I've also tried WaitForMultipleObjects() (with just a single object in the array), same problem.
(Background: I'm trying to improve input handling in the GHC Haskell compiler runtime.)
CancelSynchronousIo cancel I/O operations that are issued by the specified thread. more concrete it cancel IRP packets which associated with specified thread via call IoCancelIrp. if use undocumented NtCancelSynchronousIoFile (CancelSynchronousIo internally call it with IoRequestToCancel = 0) we can be more selective - cancel only i/o request which used specified IoRequestToCancel (system check that Irp->UserIosb == IoRequestToCancel and cancel only this requests)
but WaitForSingleObject this is not I/O request. this call not create any IRP which can be canceled. so - no way do this.
however if you use WaitForSingleObjectEx with bAlertable set to TRUE - you can break wait by queue apc to thread by using QueueUserAPC . also if use NtWaitForSingleObject instead WaitForSingleObjectEx we can also alert thread by using undocumented call NtAlertThread. in this case NtWaitForSingleObject will break with STATUS_ALERTED (note that WaitForSingleObjectEx which internally call NtWaitForSingleObject do special check for STATUS_ALERTED and in case this status - again run NtWaitForSingleObject - as result we can not break WaitForSingleObjectEx by call NtAlertThread, but NtWaitForSingleObject will be breaked.
so if you need break waiting for std input - create additional thread, which must call not CancelSynchronousIo (this senseless) but QueueUserAPC or NtAlertThread (only if you use NtWaitForSingleObject for wait). and input thread must wait in alertable state. so demo code can look like:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtAlertThread(HANDLE ThreadHandle);
VOID NTAPI OnApc(ULONG_PTR Parameter)
{
DbgPrint("OnApc(%p)\n", Parameter);
}
DWORD CALLBACK BreakWaitThread(HANDLE hThread)
{
switch (LONG status = MessageBoxW(0, L"Use Apc(yes) or Alert(No) ?", L"BreakWaitThread",
MB_ICONQUESTION|MB_YESNOCANCEL|MB_DEFBUTTON3))
{
case IDYES:
if (!QueueUserAPC(OnApc, hThread, 0))
{
DbgPrint("QueueUserAPC=%u\n", GetLastError());
}
break;
case IDNO:
if (0 > (status = NtAlertThread(hThread)))
{
DbgPrint("AlertThread=%x\n", status);
}
break;
case IDCANCEL:
DbgPrint("canceled\n");
break;
default:
DbgPrint("MessageBox=%x\n", status);
}
CloseHandle(hThread);
return 0;
}
void ConsoleLoop(HANDLE hStdIn)
{
ULONG NumberOfEvents, NumberOfEventsRead, n;
INPUT_RECORD buf[8], *p;
for (;;)
{
switch (ZwWaitForSingleObject(hStdIn, TRUE, 0))
//switch (WaitForSingleObjectEx(hStdIn, INFINITE, TRUE))
{
case WAIT_OBJECT_0:
while (GetNumberOfConsoleInputEvents(hStdIn, &NumberOfEvents) && NumberOfEvents)
{
do
{
NumberOfEventsRead = min(RTL_NUMBER_OF(buf), NumberOfEvents);
if (ReadConsoleInput(hStdIn, buf, NumberOfEventsRead, &NumberOfEventsRead) && NumberOfEventsRead)
{
n = NumberOfEventsRead;
p = buf;
do
{
if (p->EventType == KEY_EVENT)
{
DbgPrint("%u(%u) %C %x %x %x\n",
p->Event.KeyEvent.bKeyDown,
p->Event.KeyEvent.wRepeatCount,
p->Event.KeyEvent.uChar.UnicodeChar,
p->Event.KeyEvent.wVirtualKeyCode,
p->Event.KeyEvent.wVirtualScanCode,
p->Event.KeyEvent.dwControlKeyState);
if (VK_OEM_PERIOD == p->Event.KeyEvent.wVirtualKeyCode)
{
return ;//if user type '.' return for demo
}
}
} while (p++, --n);
}
else
{
FlushConsoleInputBuffer(hStdIn);
break;
}
} while (NumberOfEvents -= NumberOfEventsRead);
}
continue;
case STATUS_USER_APC:
DbgPrint("\nUSER_APC\n");
return;
case STATUS_ALERTED:
DbgPrint("\nALERTED\n");
return;
case WAIT_FAILED :
DbgPrint("\nWAIT_FAILED=%u\n", GetLastError());
return;
default:
__debugbreak();
return;
}
}
}
void SimpleDemo()
{
if (HANDLE hCurrentThread = OpenThread(THREAD_ALERT|THREAD_SET_CONTEXT , FALSE, GetCurrentThreadId()))
{
ULONG dwThreadId;
HANDLE hThread = CreateThread(0, 0, BreakWaitThread, hCurrentThread, 0, &dwThreadId);
if (hThread)
{
ConsoleLoop(GetStdHandle(STD_INPUT_HANDLE));
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
else
{
CloseHandle(hCurrentThread);
}
}
}
Console I/O is difficult to use asynchronously, it is simply not designed for it. See IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR for some possible workarounds.
If that is not an option for you, then you will have to either:
use WaitForSingleObject() in a loop with a short timeout. Create a flag variable that your loop can look at on each iteration to break the loop if the flag is set.
use WaitForMutipleObjects(), giving it 2 HANDLEs to wait on - one for the console (or whatever), and one for an event object from CreateEvent(). Then you can signal the event with SetEvent() when you want to break the wait. The return value of WaitForMutipleObjects() will tell you which HANDLE was signaled.
Can below script be modified so that the keys
"cl" fires "www.google.com" just if the "cl" keys
are both pressed for 500 milliseconds ?
Reason for this is that as part typing text sometimes the keys "cl" are pressed in rapid succession which then fires "www.google.com"
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Send, {Backspace Down}{Backspace Up}{Backspace Down}{Backspace Up}
Run, "www.google.com"
}
Return
Using A_TickCount may be a good option.
~l::
duration := 0
If (GetKeyState("c","p") && GetKeyState("l","p"))
{
start := A_TickCount
While (GetKeyState("c") && GetKeyState("l"))
Sleep, 1
duration := A_TickCount - start
}
if (duration > 500)
Run, "www.google.com"
Return
This appears to do the trick :
~c::
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Send, {Backspace Down}{Backspace Up}{Backspace Down}{Backspace Up}
sleep, 100
If (GetKeyState("c","p") && GetKeyState("l","p")) {
Run, "www.google.com"
}
Return
}
Return
Per this AutoHotKey forum post:
[T]he only way to program a key down for a specific duration is to use the down command and then a wait function with a (manually entered time) and then the up command[.]
So, you could solve this problem by putting a timer and then another if block inside your current if block, although it sounds like a bad idea.
A 500 millisecond delay could cause uncontrolled key repetition sothat we can't reliably delete the pressed keys anymore. So my suggestion is to find the repeat delay and only wait for so long minus ~150 milliseconds:
~c::
~l::
If (GetKeyState("c","p") && GetKeyState("l","p")) {
If (!GetKeyState("c","p") || !GetKeyState("l","p"))
Return
DllCall("SystemParametersInfo", UInt, 0x16, UInt, 0, UIntP, RepeatDelay, UInt, 0) ;get the key repeat delay
Sleep % (RepeatDelay+1)*250-150
If (GetKeyState("c","p") && GetKeyState("l","p")) {
SendInput, {c up}{l up}{BS}{BS}
Run, www.google.com
}
}
Return
SystemParametersInfo - SPI_GETKEYBOARDDELAY