How do I wait for a process OR if a certain window becomes the active one in AutoHotKey? - autohotkey

I have a loop that waits for a process to exist before continuing. However, I want to make it so that the loop will proceed if EITHER the process exists or a window with some certain class is present. Right now I have the following:
Loop {
Process, Wait, ProcessName.exe
; Do stuff
Sleep, 50
}
I want to be clear that I specifically used Process, Wait because I didn't want the loop to constantly running.

Instead of "ProcessName.exe" you can use "ahk_exe Process Name/Path" to identify the process.
Use "DetectHiddenWindows, On" if there's no visible window of this process.
This way you can create a window group with GroupAdd that contains both the process and the window.
Replace "Process, Wait, ProcessName.exe" with "WinWait, ahk_group GroupName" in the loop.

Related

distinguish between different instances or windows of a process and find their PID instead of their owner PID to send input event in macOS?

If I open multiple windows/tabs of a browser, and I want to distinguish between them so that I can control those windows individually from my application, what is the approach? If I send command programmatically to a process with PID id it will send that command to the most recently active window but I want to send command to all the window of that process. If I query for PID of running process with CGWindowListOption I get owner PIDs of running processes. let windowsListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
I need to know and use something that will trigger multiple window/process at the same time. Is there a different PID of different window of the same process? For example: Chrome tab 1 has a pid, tab 2 will have another pid. How to find those PIDs instead of the owner PID only?
So how can I find out different process id or similar attribute of a process with multiple window with same owner PID?
This activates each window in TextEdit and sends a space keystroke.
activate application "TextEdit"
tell application "System Events"
tell application process "TextEdit"
repeat with theWindow in windows
perform action "AXRaise" of theWindow
keystroke " "
end repeat
end tell
end tell
But to note how this would work without pressing keys, the following appends "A" to all the currently open documents without bringing anything to the foreground or interfering with the user's input.
tell application "TextEdit"
repeat with theDocument in documents
set text of theDocument to (text of theDocument) & "A"
end repeat
end tell
Whenever possible, you want things like this rather than sending keystrokes.

How to use pause with openvar in a for loop

Using the following code:
tmpTable = table([1;2;3]);
for i = 1:5
openvar tmpTable
pause
end
When I run the for loop, all I get is a blank screen in the Variable Editor, except the dimensions of the table are displayed correctly. If I break from the for loop the table displays correctly.
My question is, how do I make this table display programmatically in the for loop, with a pause like command that allows me to inspect the table before moving onto the next one?
What's happening is that pause is pausing the main MATLAB thread which is why you aren't seeing anything in the Variable Editor. You have to make MATLAB enter debug mode if you want the main MATLAB thread to be free.... or of course break the loop as you have discovered.
A "hackish" way to get things going is to insert a keyboard statement instead of pause to force MATLAB to go into debug mode. Once you're there, you'd have to use dbcont to continue onto the next iteration of the loop. This will make MATLAB enter debug mode again as the keyboard statement will be encountered again thus freeing the main thread. This repeats until the last iteration.
Therefore:
tmpTable = table([1;2;3]);
for i = 1:5
openvar tmpTable
keyboard; %// Change
end
You will then see K>> once you execute the first iteration of the loop when you look at the Command Prompt. This signifies that you are in debug mode. To proceed to the next iteration, type in dbcont in the Command Prompt and push ENTER. You can reuse the last command by pushing the Up arrow on your keyboard then push ENTER again and keep doing this until the last iteration of your loop. You will unfortunately have to click back in the Command Prompt as the focus will be placed on the Variable Editor before you enter in the command again. If at any time you want to quit debug mode, use dbquit. This will terminate any code execution and bring you back to the Command Prompt.
This is the only way really to free up the main MATLAB thread at each iteration that I know of.

Powershell: Uninstall Software that has prompts for user input

Does anybody know if it is possible to uninstall software through PowerShell if it prompts for user input? I have multiple scripts that can uninstall just about anything, except for the one software that I need it to uninstall. I'm specifically trying to uninstall PDFForge toolbar which is installed when downloading PDFCreator.
None of the scripts that I've written fail, they just hang when run, I believe because the uninstall process is asking for user input to proceed.
PowerShell isn't going to interact with the prompts... you can't just tell it to click "Next" in an executable because it can't see it.
You can send keys to it though. You're really just using COM objects.
So, first, get your process ID by setting a variable that contains an array, the data for which is defined by the name of your process. Let's say your process is called, "Uninstall" and the process is ALREADY RUNNING:
$a = Get-Process | ?{$_.Name -eq "Uninstall"}
Start the COM:
$wshell = New-Object -ComObject wscript.shell;
Bring the uninstallation program with this process ID to the front so we can send it keystrokes:
$wshell.AppActivate($a.id)
Give it a few seconds to bring that window forward. I chose 5, but if your machine isn't stressed, 2 is probably enough:
Start-Sleep 5
Now start telling it what keys you want to send. The syntax here is this: whatever is in the () is what will be sent. The position in the single-quote is the keystroke to send, after the comma is how long you want it to wait before proceeding. Assuming the first screen is "Next" you can send your first command by telling PowerShell to send the ENTER key and wait 5 seconds:
$wshell.SendKeys('~',5)
The wait function is optional, but for your purposes, you're definitely going to want it. (If you don't want it $wshell.SendKeys('~') would send the ENTER key and immediately move to the next command.)
Walk through the uninstallation yourself manually, using all keystrokes, and for any keystroke you send, pay attention to how long it takes before the next part of uninstallation is loaded, and wait longer than that with your script (e.g. if it processes your ENTER key instantaneously, I'd have it wait 3 or 5 seconds before it sends the next command. If it takes 5 seconds to load, I'd tell it to wait 10 seconds before sending the next command).
Letters are letters, and numbers are numbers. Most non-commands are just assigned to their keys (meaning if you want to type "K" your command would just be $wshell.SendKeys('K')) You can get the rundown for the specific keys here: https://msdn.microsoft.com/en-us/library/office/aa202943(v=office.10).aspx.

AHK (AutoHotKey): Taking focus away from InputBox

Immediately after calling:
inputbox,inv,Scan Invoice Number:
I want to take focus away from the inputbox and to another window but it does not behave as expected and waits for user input before moving on to the next line of code. Is there any way to override this behaviour?
InputBox makes the current thread wait for user input and therefore suspends the thread. In other languages, you'd say the Thread terminates and an ActionListener starts listening. Multithreading itself cannot actively be achieved by calling a new Thread directly in AutoHotkey, you can, however, as stated in the documentation, launch one with a hotkey or a timed subroutine.
I came up with the following solution for myself a couple of times, afaik it's the cleanest way there is:
setTimer, continueAfterInputbox, -100 ; a negative period indicates "run once only", after a sleep of 100 ms in this case
inputbox, inv, Scan Invoice Number:
;; do things with %inv%
Return
continueAfterInputbox:
msgbox, do other cool things
return

Stop a script in Matlab

My question is, how do I stop a script by a pressing a GUI button? I already tried to write a code that simulates "CTRL+C" press, but it doesn't work.
I'm not sure there's a way to stop another script from being called. One alternative would be to set a global variable that's periodically checked by the script you wish to stop. If you set the value of a "stop processing" variable to true in your callback, the other script could stop if it found that it was supposed to stop.
Edit
If you'd like to have a GUI option to stop an ongoing process, I would recommend you take a look at something like STOPLOOP on the MATLAB File Exchange.
I won't write the code for you but here's a high-level way to accomplish this:
Display a waitbar with a button on it. Create a callback function for the button which sets a flag to true.
Begin computation inside of a for-loop. In the loop:
1. update the waitbar.
2. call the drawnow function so that the callback is executed properly. Remember MATLAB is single-threaded, so this is necessary or the callback will not execute until the script finishes.
3. perform any other computation
4. check for the flag set to true. if it is true, return to stop execution.
The flag could be a global variable, or a handle-based object (so that it is passed by reference).
EDIT:
This answer is not applicable for the current question.
This answer is applicable only for scripts having the first line = #!/usr/bin/matlab
use pkill without option will send a TERM signal:
pkill yourscriptname
If you really want the same signal as CTRL+C then:
pkill -3 yourscriptname
If your script still does not stop, you can use the most aggressive signal KILL:
pkill -9 yourscriptname
Of course, if you known the PID (Process IDentifier), you can simply use kill:
kill yourPID
kill -3 yourPID
kill -9 yourPID
You can have more info about signals using one of these commands:
man 7 signal
kill -l
info signal
I don't do a lot of GUIs, but for debugging purposes I would try to set the button callback to #keyboard. That is, something like:
set(handleToGuiButton,'Callback',#keyboard)
To actually stop execution you would need to somehow communicate this button press into the loop that was executing, for example via global variables, or something fancier (e.g. https://stackoverflow.com/a/8537460/931379)
But I would honestly look at the stoploop link (from another answer) before going down any of these routes.