Stop AutoKey script if Window is not match and print the ShortCut literal - autokey

i use a AutoKey (autokey-gtk 0.95.10) script with the shortcut ü
it get errors with:
winTitle = window.get_active_title()
winClass = window.get_active_class()
if winTitle != "0 A.D." or winClass != 'pyrogenesis.pyrogenesis':
keyboard.send_keys("ü")
but not with shorter Version:
winTitle = window.get_active_title()
if winTitle != "0 A.D.":
keyboard.send_keys("ü")
got Errors and the CPU is really high at 7%:
If i run this AutoKey (autokey-gtk 0.95.10) script again it show no errors but does nothing.
CPU still high and i need to shutdown it (no normal exit).
i don't understand why this happens. BTW as workaround its good enough for me to check only the window name. The better solution should check for class and window name.

Related

Ruby spawn process, capturing STDOUT/STDERR, while behaving as if it were spawned regularly

What I'm trying to achieve:
From a Ruby process, spawning a subprocess
The subprocess should print as normal back to the terminal. By "normal", I mean the process shouldn't miss out color output, or ignore user input (STDIN).
For that subprocess, capturing STDOUT/STDERR (jointly) e.g. into a String variable that can be accessed after the subprocess is dead. Escape characters and all.
Capturing STDOUT/STDERR is possible by passing a different IO pipe, however the subprocess can then detect that it's not in a tty. For example git log will not print characters that influence text color, nor use it's pager.
Using a pty to launch the process essentially "tricks" the subprocess into thinking it's being launched by a user. As far as I can tell, this is exactly what I want, and the result of this essentially ticks all the boxes.
My general tests to test if a solution fits my needs is:
Does it run ls -al normally?
Does it run vim normally?
Does it run irb normally?
The following Ruby code is able to check all the above:
to_execute = "vim"
output = ""
require 'pty'
require 'io/console'
master, slave = PTY.open
slave.raw!
pid = ::Process.spawn(to_execute, :in => STDIN, [:out, :err] => slave)
slave.close
master.winsize = $stdout.winsize
Signal.trap(:WINCH) { master.winsize = $stdout.winsize }
Signal.trap(:SIGINT) { ::Process.kill("INT", pid) }
master.each_char do |char|
STDOUT.print char
output.concat(char)
end
::Process.wait(pid)
master.close
This works for the most part but it turns out it's not perfect. For some reason, certain applications seem to fail to switch into a raw state. Even though vim works perfectly fine, it turned out neovim did not. At first I thought it was a bug in neovim but I have since been able to reproduce the problem using the Termion crate for the Rust language.
By setting to raw manually (IO.console.raw!) before executing, applications like neovim behave as expected, but then applications like irb do not.
Oddly spawning another pty in Python, within this pty, allows the application to work as expected (using python -c 'import pty; pty.spawn("/usr/local/bin/nvim")'). This obviously isn't a real solution, but interesting nonetheless.
For my actual question I guess I'm looking towards any help to resolving the weird raw issue or, say if I've completely misunderstood tty/pty, any different direction to where/how I should look at the problem.
[edited: see the bottom for the amended update]
Figured it out :)
To really understand the problem I read up a lot on how a PTY works. I don't think I really understood it properly until I drew it out. Basically PTY could be used for a Terminal emulator, and that was the simplest way to think of the data flow for it:
keyboard -> OS -> terminal -> master pty -> termios -> slave pty -> shell
|
v
monitor <- OS <- terminal <- master pty <- termios
(note: this might not be 100% correct, I'm definitely no expert on the subject, just posting it incase it helps anybody else understand it)
So the important bit in the diagram that I hadn't really realised was that when you type, the only reason you see your input on screen is because it's passed back (left-wards) to the master.
So first thing's first - this ruby script should first set the tty to raw (IO.console.raw!), it can restore it after execution is finished (IO.console.cooked!). This'll make sure the keyboard inputs aren't printed by this parent Ruby script.
Second thing is the slave itself should not be raw, so the slave.raw! call is removed. To explain this, I originally added this because it removes extra return carriages from the output: running echo hello results in "hello\r\n". What I missed was that this return carriage is a key instruction to the terminal emulator (whoops).
Third thing, the process should only be talking to the slave. Passing STDIN felt convenient, but it upsets the flow shown in the diagram.
This brings up a new problem on how to pass user input through, so I tried this. So we basically pass STDIN to the master:
input_thread = Thread.new do
STDIN.each_char do |char|
master.putc(char) rescue nil
end
end
that kind of worked, but it has its own issues in terms of some interactive processes weren't receiving a key some of the time. Time will tell, but using IO.copy_stream instead appears to solve that issue (and reads much nicer of course).
input_thread = Thread.new { IO.copy_stream(STDIN, master) }
update 21st Aug:
So the above example mostly worked, but for some reason keys like CTRL+c still wouldn't behave correctly. I even looked up other people's approach to see what I could be doing wrong, and effectively it seemed the same approach - as IO.copy_stream(STDIN, master) was successfully sending 3 to the master. None of the following seemed to help at all:
master.putc 3
master.putc "\x03"
master.putc "\003"
Before I went and delved into trying to achieve this in a lower level language I tried out 1 more thing - the block syntax. Apparently the block syntax magically fixes this problem.
To prevent this answer getting a bit too verbose, the following appears to work:
require 'pty'
require 'io/console'
def run
output = ""
IO.console.raw!
input_thread = nil
PTY.spawn('bash') do |read, write, pid|
Signal.trap(:WINCH) { write.winsize = STDOUT.winsize }
input_thread = Thread.new { IO.copy_stream(STDIN, write) }
read.each_char do |char|
STDOUT.print char
output.concat(char)
end
Process.wait(pid)
end
input_thread.kill if input_thread
IO.console.cooked!
end
Bundler.send(:with_env, Bundler.clean_env) do
run
end

How to execute an external command asynchronously in gVim 8.1 without starting a new cmd every time and append the output to an existing buffer

I want to execute a batch file and display the output on a new buffer. I know I can use !start for this, but I can't figure out how to make it reuse the same command-line instead of starting a new one every time.
I managed to get close by using :terminal instead with send_keys(), checking if the terminal buffer still exists and only starting a new one when it doesn't. The problem with this is that what I get is an interactive shell, so I have to switch to Terminal-Normal mode to be able to navigate the contents of the buffer otherwise cmd steals focus from vim and doesn't let me move around. Also the prompt itself is part of the output, which is annoying.
Here's the code:
fun! MatchAnyInList(list, value)
return index(map(a:list, 'v:val =~# "' . a:value . '"'), 1) >= 0
endfun
" I have no idea what I'm doing
fun! RunBuildBatchFile()
if !exists("g:terminal_bufnum") || MatchAnyInList(['finished', ''], term_getstatus(g:terminal_bufnum))
let g:terminal_bufnum = term_start("cmd", {'hidden': 1})
call term_sendkeys(g:terminal_bufnum, "vcvarsall x64\<CR>")
endif
if bufwinnr(g:terminal_bufnum) < 0
execute "botright sb " . g:terminal_bufnum
call term_setsize(g:terminal_bufnum, 4, 0)
endif
call term_sendkeys(g:terminal_bufnum, "cls\<CR>")
call term_sendkeys(g:terminal_bufnum, "C:\\Path\To\Executable\Command.exe")
if term_getstatus(g:terminal_bufnum)=~# "normal"
call feedkeys("i")
endif
endfun
There's probably a much better way of doing this. I tried looking for information about this stuff online and in the docs but I didn't get anywhere. Any ideas?

Debugging with GDB - seeing code around a given breakpoint

I am trying to debug a C++ program using GDB. I have set 15 breakpoints. Most of the breakpoints are in different files. After the first 5 breakpoints, it became difficult to remember what line of code any given breakpoint refers to.
I struggle quite a bit simply trying to recall what a given breakpoint refers to. I find this quite distracting. I was wondering if there is a way to tell gdb to display code around a certain breakpoint.
Something like this - $(gdb) code 3 shows 30 lines of code around breakpoint 3. Is this possible today. Could you please show me how?
I run gdb in tui mode, and I also keep emacs open to edit my source files.
You can use gdb within emacs.
In emacs, type M-x gdb, after entering the name of the executable, type M-x gdb-many-windows. It brings up an IDE-like interface, with access to debugger, locals, source, input/output, stack frame and breakpoints.
You can find a reference and snapshot here.
I don't think you can do it exactly like this in gdb as such, but it can be scripted in gdb python.
This crude script should help:
import gdb
class Listbreak (gdb.Command):
""" listbreak n Lists code around breakpoint """
def __init__ (self):
super(Listbreak, self).__init__ ("listbreak", gdb.COMMAND_DATA)
def invoke (self, arg, from_tty):
printed = 0
for bp in gdb.breakpoints():
if bp.number == int(arg[0]):
printed = 1
print ("Code around breakpoint " + arg[0] + " (" + bp.location + "):")
gdb.execute("list " + bp.location)
if printed == 0:
print ("No such breakpoint")
Listbreak()
Copy this to listbreak.py, source it in gdb (source listbreak.py), then use it like this:
listbreak 2

Is there any method to detect whether STDIN has been redirected within VBscript?

I'm trying to process/filter input within a VBscript, but only if the input has been piped into the script. I don't want the script processing user/keyboard input. I'd like to code this as something like this:
stdin_is_tty = ...
if not stdin_is_tty then
...
input = WScript.StdIn.ReadAll
end if
Otherwise, the script will hang, waiting on user input when it executes WScript.StdIn.ReadAll (or even earlier if I test the stream with WScript.StdIn.AtEndOfStream).
In C#, I'd use:
stdin_is_tty = not System.Console.IsInputRedirected // NET 4.5+
The accepted answer for Q: "How to detect if Console.In (stdin) has been redirected?" shows how to build that result using Win32 calls via P/Invoke, for versions of NET earlier than NET 4.5. But I don't know of any way to translate that method into VBscript.
I've constructed a clumsy, partial solution using SendKeys to send an end-of-stream sequence into the scripts' keyboard buffer. But the solution leaves keys in the buffer if STDIN is redirected, which I can't clean up unless I know that STDIN was redirected... so, same problem.
I'd prefer to keep the script in one packaged piece, so I'd rather avoid a separate wrapping script or anything not available on a generic Windows 7+ installation.
Any brilliant ideas or workarounds?
EDIT: added copy of initial solution
I've added a copy of my improved initial solution here (admittedly, a "hack"), which now cleans up after itself but still has several negatives:
input = ""
stdin_is_tty = False
test_string_length = 5 ' arbitrary N (coder determined to minimize collision with possible inputs)
sendkey_string = ""
test_string = ""
for i = 1 to test_string_size
sendkey_string = sendkey_string & "{TAB}"
test_string = test_string & CHR(9)
next
sendkey_string = sendkey_string & "{ENTER}"
wsh.sendkeys sendkey_string ' send keyboard string signal to self
set stdin = WScript.StdIn
do while not stdin.AtEndOfStream
input = input & stdin.ReadLine
if input = test_string then
stdin_is_tty = True
else
input = input & stdin.ReadAll
end if
exit do
loop
stdin.Close
if not stdin_is_tty then
set stdin = fso.OpenTextFile( "CON:", 1 )
text = stdin.ReadLine
stdin.Close
end if
This solution suffers from the three problems:
leaving a visible trace at the command line (though now, just a single blank line which is low visibility)
possible collision of the test string (a set series of N [coder determined] TABs followed by a NEWLINE) with the first line of any redirected input causing a false positive redirection determination. Since the number of TABs can be modified, this possibility can be made arbitrarily low by the coder.
a race condition that if another window receives focus before the SendKeys portion is executed, the wrong window will receive the code string, leading to a false negative redirection determination. My estimate is that the possibility of this circumstance occurring is very low.
In short, no, but ...
I've tested everything i could think of and have not found a reasonable way to do it.
None of the properties/methods exposed by the TextStream wrappers retrieved with WScript.StdIn or fso.GetStdStream give enough information to determine if the input is redirected/piped.
Trying to obtain information from the behaviour/environment of a spawned process (how to create the executable is other story) is also unlikely to be useful because
WshShell.Execute always spawns the process with its input and output handles redirected
WshShell.Run creates a new process that does not inherit the handles of the current one
Shell.Application.ShellExecute has the same problem as WshShell.Run
So, none of these methods allow the spawned process to inherit the handles of the current process to check if they are redirected or not.
Using WMI to retrieve information from the running process does not return anything usable (well, HandleCount property for the process differs when there is a redirection, but it is not reliable)
So, not being able to determine from vbs code if there is a redirection, the remaining options are
Don't detect it: If the piped input must be present, behave as the more command and in all cases try to retrieve it
Indicate it: If the pipe input is not always required, use an argument to determine if the stdin stream needs to be read.
In my case, I usually use a single slash / as argument (for coherence with some of the findstr arguments that also use a slash to indicate stdin input). Then in the vbs code
If WScript.Arguments.Named.Exists("") Then
' here the stdin read part
End If
Check before: Determine if there is redirection before starting the script. A wrapper .cmd is needed, but with some tricks both files (.cmd and .vbs) can be combined into one
To be saved as .cmd
<?xml : version="1.0" encoding="UTF-8" ?> ^<!------------------------- cmd ----
#echo off
setlocal enableextensions disabledelayedexpansion
timeout 1 >nul 2>nul && set "arg=" || set "arg=/"
endlocal & cscript //nologo "%~f0?.wsf" //job:mainJob %arg% %*
exit /b
---------------------------------------------------------------------- wsf --->
<package>
<job id="mainJob">
<script language="VBScript"><![CDATA[
If WScript.Arguments.Named.Exists("") Then
Do Until WScript.StdIn.AtEndOfStream
WScript.StdOut.WriteLine WScript.StdIn.ReadLine
Loop
Else
WScript.StdOut.WriteLine "Input is not redirected"
End If
]]></script>
</job>
</package>
It is a .wsf file stored inside a .cmd. The batch part determines if the input is redirected (timeout command fails to get a console handle on redirected input) and pass the argument to the script part.
Then, the process can be invoked as
< inputfile.txt scriptwrapper.cmd input redirected
type inputfile.txt | scriptwrapper.cmd input piped
scriptwapper.cmd no redirection
While this is a convenient way to handle it, the invocation of the .wsf part from the .cmd, while being stable and working without problems, relies in an undocumented behaviour of the script host / cmd combination.
Of course you can do the same but with two separate files. Not as clean, but the behaviour is documented.

Can a Win32 console application detect if it has been run from the explorer or not?

I have to create a console application which needs certain parameters. If they are missing or wrong I print out an error message.
Now the problem: If someone starts the program from the explorer by double-clicking the console window disappears immediately. (But the application is not entirely useless from the explorer, you could drag files onto it and it would work)
I could always wait for a keypress, but I don't want that if the user did start it from the command line.
Is there some way to distinguish between these situations?
See http://support.microsoft.com/kb/99115, "INFO: Preventing the Console Window from Disappearing".
The idea is to use GetConsoleScreenBufferInfo to determine that the cursor has not moved from the initial 0,0 position.
Code sample from #tomlogic, based on the referenced Knowledge Base article:
// call in main() before printing to stdout
// returns TRUE if program is in its own console (cursor at 0,0) or
// FALSE if it was launched from an existing console.
// See http://support.microsoft.com/kb/99115
#include <stdio.h>
#include <windows.h>
int separate_console( void)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE), &csbi))
{
printf( "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
return FALSE;
}
// if cursor position is (0,0) then we were launched in a separate console
return ((!csbi.dwCursorPosition.X) && (!csbi.dwCursorPosition.Y));
}
GetConsoleTitle()
I've seen code which performs
if (!GetConsoleTitle(NULL, 0) && GetLastError() == ERROR_SUCCESS) {
// Console
} else {
// GUI
}
BUT... I've found that AttachConsole() is more helpful
In C++ (off the top of my head, and I'm no C++ programmer)
if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
// GUI
} else {
// Console, and you have a handle to the console that already exists.
}
Is more effective. Additionally, if you find yourself in a GUI environment and would like to stay there as long as you can, but later find something catastrophic has happened that could really use a dump to a console window (you can't be arsed writing an edit box window to lot it to or attach to the NT System log and throw up a MessageBox()) well then you can AllocConsole() later on in the process, when GUI methods have failed.
I've found a much better solution using GetConsoleProcessList to get the attached process count to the current console.
If this process is the only one attached it will be closed when the process exists.
I found it in a post https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
But it had a bug (at least in windows 10) since the documentation forbids invoking this function with null.
My solution was:
DWORD procId;
DWORD count = GetConsoleProcessList(&procId, 1);
if (count < 2) ...
I believe cmd.exe sets the CMDCMDLINE and CMDEXTVERSION environemntal variables when it starts. So if these are set your program was most probably started from a shell.
This isn't foolproof but it's something.
It's also possible to determine your parent PID in a few convoluted and possibly unreliable ways, or so I gather. You may want to look into that.
Here is the excellent answer from #DanielBenSassoon adapted for C#. Tested in Visual Studio 2019 and Windows 10.
// Gets a list of the process IDs attached to this console
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint GetConsoleProcessList(uint[] processList, uint processCount);
public static bool IsFinalProcess()
{
// See: https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
uint[] procIDs = new uint[64];
uint processCount = GetConsoleProcessList(procIDs, 64);
return (processCount < 2);
}
This approach allows you to distinguish between four scenarios:
Debugging from the IDE (F5) [process count = 1]
Running from the IDE, but not debugging (Ctrl + F5) [process count = 2]
Double-clicking in Explorer [process count = 1]
Running from a command-prompt window [process count = 2]
When IsFinalProcess is true, you can use Console.ReadKey(false); to prevent the console window from disappearing after your application exits.
EDIT: I've been using this .bat/.cmd wrapper successfully for a couple of years now:
#ECHO OFF
REM Determine if script was executed from an interactive shell
(echo %CMDCMDLINE% | find /i "%~0" >NUL 2>&1) && (set IS_INTERACTIVE=false) || (set IS_INTERACTIVE=true)
<call console application here>
REM Wait for keystroke
if "%IS_INTERACTIVE%" == "false" (
echo.
echo Hit any key to close.
pause >NUL 2>&1
)
The advantage here is that this will work for all console applications, be it your own or someone else's (for which you might not have sources you could modify). The downside is, well, that you have a separate wrapper.
My original answer back in 2014 was this:
This works like a charm:
#echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" goto nonconsole
:console
<do something>
goto exit
:nonconsole
<do something>
pause
:exit
Copied from this thread. I also tried evaluating %cmdcmdline% myself, however there's an issue regarding quote characters ("), which prevents something like if "%cmdcmdline%" == "%ComSpec%" goto [target] from working.

Resources