Capture Send with Input - autohotkey

I have a script that I use to insert special characters and implement dead keys. The special characters are inserted with SendEvent. When a dead key is activated, the script runs Input, key, L1 and looks up the result in a table to find a composed character.
This works fine for real keypresses, but if I trigger a dead key and then cause a special character to be inserted with SendEvent, the Input call doesn't notice it. The special character is inserted verbatim and the next real keypress will go to the Input call.
How can I alter my script so that special characters inserted by the script will be captured by Input?
I am running a minimal script to demonstrate the issue:
SpecialCharacter(char) {
SendEvent %char%
}
DeadKey(combining) {
Input, key, L1
SendEvent %key%
SendEvent %combining%
}
^q::SpecialCharacter("a")
^w::DeadKey("b")
^ESC::Reload
The actual application will be more complex.
Actual output:
Ctrl-q: a
Ctrl-w, x: xb
Ctrl-w, Ctrl-q: no output
Ctrl-w, Ctrl-q, x: xb
Desired output:
Ctrl-w, Ctrl-q: ab
Ctrl-w, Ctrl-q, x: abx
I tried fiddling around with SendLevel/#InputLevel, but I don't think that those affect the behavior of the Input command.

Related

How to write a test to confirm that a perl script waits (or doesn't wait) for interactive user input (based on supplied options)

I have a perl script for which I would like to write a few tests. If the perl script gets supplied a specific option, the user is allowed to paste or type out multi-line input and end their input using control-d.
These are the tests I want to write:
The script (when an interactive flag is supplied) waits for (multiple lines of) input on STDIN until the user hits control-d
[this test is already implemented - but provided for completeness] The script (when a flag is supplied that indicates a redirect/pipe) consumes all input on STDIN and does not wait for control-d
The script (when no input flag is provided [interactive or redirect]) does not wait for interactive user input
Test 1 toy example
I wrote a test for test 1 that confirms input was received (it works by the parent test script printing to the child's input handle and the child modifies and prints that input back out), but that test doesn't wait for an end of input signal (e.g. control-d) (which I don't know how to send anyway). So in other words, I can confirm it receives input, but I don't know how to confirm that it waits for the user to intentionally end the input entry. I.e. How do I know that the input consumption won't stop until the user types control-d?
Here's what I have so far for test 1. I wrote a 3rd little IO::Pipe::Consumer module to be able to send input to the child process that I'm testing and I wrote a toy example of the script that allows input on STDIN from a tty.
Here is a toy version of the script I'm testing:
>perl -e 'while(<STDIN>){print("*$_")}'
test
*test
^d
>
And here is the toy test code (that I want to improve) for the above script:
>perl -e '
use IO::Pipe::Consumer;
$obj = new IO::Pipe::Consumer;
$si = $obj->getSubroutineConsumer(
sub { while(<STDIN>) print("*$_") } }
);
print $si "test\n"
'
*test
>
I thought the parent would have to print an EOF (e.g. like what you get from "control-d") to end the input in the test, but the test ends immediately even though I'm not sending any such end-of-input character. I can see that it's getting, modifying, and printing the input. Is that sufficient to confirm that the script will wait for user input (and that the user will be able to intentionally end the input) or is there something else I should do to confirm it waits for all user input until the user intends to end it?
Test 2 - done
Test 3 toy - don't know how to write it...
Even if modified input spit back out is sufficient proof of "waiting for input" for test 1, I also wish to test that a script doesn't consume input on STDIN when no input option (interactive or redirect) is provided - but since it doesn't seem to wait even when I do send it input without an end-of-input signal, how would I test that the script wouldn't hang waiting for input? Note, the script has other options for consuming redirected or piped input, so my intent is specifically to know if it's waiting on input from the tty. All of the STDIN consumption options (whether from the tty or via redirect/pipe) are optional, which is why I want to write these tests.
My manual testing shows everything works as intended. I would just like some tests to assure that behavior for the future.
IO::Pipe::Consumer
I feel like the thing I'm missing is not relevant to IO::Pipe::Consumer, so WRT that, I'll just describe it instead of paste in 30 or so lines of code... All it does is it sets a pipe to the child's STDIN and gives that handle back to the parent for it to print to. I haven't put it on cpan. I'm just experimenting to see if I can use it to write these tests.
IO::Pipe::Consumer is basically the opposite of IO::Pipe::Producer (a module I published on cpan looong ago, say 2001-ish, when I was new to perl, or programming for that matter). The main difference, aside from swapping STDIN for STDOUT and Reader with Writer (and vice versa), is that the open is open(STDIN,"<",\${$stdin_pipe}).
I thought the parent would have to print an "end-of-input" (e.g. "control-d") character to end the input in the test,
Ctrl-D doesn't produce an "end of input character"; it causes the terminal to return EOF.
I don't know what IO::Pipe::Consumer is —it's not on CPAN— but I presume it creates a pipe. Exiting the program causes the writer end of the pipe to be closed and thus cause the reader end to return EOF.
is there something else I should do to confirm it waits for all user input until the user intends to end it?
<> reads until one of the following things happen:
A line feed is encountered (returning what was read including the line feed)
EOF is encountered (returning what was read up to an including the line feed)
An error is encountered (returning false).
You can confirm it waits by putting sleep statements between what you send. Be aware that buffering may interfere.

AHK and US-INT keyboard: Why are "dead" keys no longer swallowed?

I normally use the United States-International keyboard layout. This layout has several keys set as "dead" keys for diacritic marks - for example, pressing ^ is a dead key; it appears to do nothing until the next key is hit; if that key is one that the circumflex is an allowable diacritic, it replaces it with the marked key - that is, if I press ^ then a, I will get â - but if I press a key that it's not an allowed diacritic for, I will get the circumflex followed by the letter, e.g., ^ follows by h gives me ^h.
I wrote a AHK script that adds the diacriticalized characters for Esperanto (see below). It used to work "transparently" and matched the behavior described above. However, recently, the behavior seems to have changed: it no longer "swallows" the diacritic, and inserts a backspace before inserting the character desired.
In other words, if I type "The Esperanto character that sounds like English 'ch' is " and then type ^ then c, it replaces the space following "is" with the ĉ, and on the next keystroke, whatever it is, acts like I had hit ^ then that key.
Why? and How do I fix this?
#Hotstring ? C *
; Esperanto diacriticalized characters
::^c::ĉ
::^C::Ĉ
::^g::ĝ
::^G::Ĝ
::^h::ĥ
::^H::Ĥ
::^j::ĵ
::^J::Ĵ
::^s::ŝ
::^S::Ŝ
::~u::ŭ
::~U::Ŭ
Don't know if I maybe missed something simple with hotstrings, but I couldn't really make it work without trying to do some even further trickery.
I figured an InputHook(docs) implementation could work pretty well.
It might be overkill/stupid though, since it basically just creates a custom implementation for a hotstring. But well, at least it works.
key_map := { "c": "ĉ"
, "g": "ĝ"
, "h": "ĥ"
, "j": "ĵ"
, "s": "ŝ"
, "u": "ŭ" }
ih := InputHook("V")
ih.OnChar := Func("OnChar")
ih.Start()
OnChar(_, char)
{
if (StrLen(char) != 2 || SubStr(char, 1, 1) != "^" || !(key := diacriticalize(SubStr(char, 2))))
return
fObj := Func("SendReplacement").Bind(key)
SetTimer, % fObj, -0
}
diacriticalize(key)
{
global key_map
if key is upper
return Format("{:U}", key_map[key])
else
return key_map[key]
}
SendReplacement(key)
{
SendInput, % "{BS 2}" key
}
So what's happening?
First a map for the key replacements is defined.
Adding any extra dead key combinations for ^ will work just fine.
The input hook is created with only the V(docs) option.
This makes it so that it doesn't consume input while processing it.
Then, with .OnChar(docs) we define a function that runs every time the input receives a new character.
The functions always receives just one character, except when a dead key is used it'll receive e.g ^c.
This is why we check if the input length is two and why we use SubStr()(docs) to transform ^c to just c.
SubStr(char, 1, 1) != "^" also ensures that the pressed deadkey was ^, and not e.g ¨. Otherwise ¨c would produce ĉ.
Then in the user defined function diacriticalize() we return the corresponding diacriticalized key from the key_map (if possible). If the input key was in uppercase, return the diacriticalized key in uppercase as well.
If there is no matching key in the key_map, nothing is returned. Which makes the || !(key := ...) part do its trick to also return if the input key wasn't valid.
Then the timer(docs) trickery is done just to execute the replacement outside of the OnChar() function in another thread to avoid problems with send command running too early.
Basically the period -0 just means to run once immediately.
The function which the timer will is defined as a function object that has a parameter (the key) bound to it with .Bind()(docs).
OK, I’m not sure why it works this way, but I was able to get it working by turning off the automatic backspacing and manually adding my own. The revised AHK script is as follows:
#Hotstring ? C * B0
; Acts only as a supplement to a keyboard that (a) does not
; have these characters defined _and_ uses ^ and ~ as "dead"
; keys to apply accents.
::^c::{bs 2}ĉ
::^C::{bs 2}Ĉ
::^g::{bs 2}ĝ
::^G::{bs 2}Ĝ
::^h::{bs 2}ĥ
::^H::{bs 2}Ĥ
::^j::{bs 2}ĵ
::^J::{bs 2}Ĵ
::^s::{bs 2}ŝ
::^S::{bs 2}Ŝ
::~u::{bs 2}ŭ
::~U::{bs 2}Ŭ
::^::^
::~::~
The B0 in the #Hotstring directive turns off the automatic backspacing. With that option in effect in the original script, typing ^c would result in ^cĉ, so by inserting two backspaces before it ({bs 2}), I get rid of the extraneous ^c before inserting the ĉ.
The last two lines, replacing the caret and tilde with themselves, don’t have an obvious explanation for the reason that they're needed, but they ensure that the behavior is consistent with the standard deadkey usage, so that if I type ^spacec I get the expected ^c instead of an unexpected ĉ.

autohotkey if statement with and without curly braces

I don't understand the difference between Autohotkey's If and If(...)
According to everything I have found, If(...) behaves as "expected" but there is something not working with my code.
Below does not work. It seems the statement in the If is never evaluated, %TimeString% is never set and nothing is output:
CapsLock & T::
Input Key, L1
If (Key=T)
{
FormatTime, TimeString,, HHmm
}
Send %TimeString%
Below does work, %TimeString% is set and the time is output.
CapsLock & T::
Input Key, L1
If Key=T
FormatTime, TimeString,, HHmm
Send %TimeString%
Autohotkey has two different syntaxes: legacy and expression. This also affects the if statement.
When you use parenthesis, if (expression) is used and Key is compared to the variable T which doesn't exist and is the same as an empty variable which doesn't equal T. You need to changed it to If (Key="T") and then it will compare the variable Key to the String "T" and it will work.
In the second case you're using the traditional(legacy) If which compares the variable Key to the String T and because they are equal, it works.
The curly braces { } just define a block, they do nothing and change nothing when your block contains only one line.
Are you sure this code is identical to your script? Beause
Tjs := T
if (Tjs=T)
{
MsgBox true
}
works fine for me.

How to use command line arguments in Fortran?

GCC version 4.6
The Problem: To find a way to feed in parameters to the executable, say a.out, from the command line - more specifically feed in an array of double precision numbers.
Attempt: Using the READ(*,*) command, which is older in the standard:
Program test.f -
PROGRAM MAIN
REAL(8) :: A,B
READ(*,*) A,B
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
The execution -
$ gfortran test.f
$ ./a.out 3.D0 1.D0
This did not work. On a bit of soul-searching, found that
$./a.out
3.d0,1.d0
4.0000000000000000 0
does work, but the second line is an input prompt, and the objective of getting this done in one-line is not achieved. Also the COMMAND_ARGUMENT_COUNT() shows that the numbers fed into the input prompt don't really count as 'command line arguments', unlike PERL.
If you want to get the arguments fed to your program on the command line, use the (since Fortran 2003) standard intrinsic subroutine GET_COMMAND_ARGUMENT. Something like this might work
PROGRAM MAIN
REAL(8) :: A,B
integer :: num_args, ix
character(len=12), dimension(:), allocatable :: args
num_args = command_argument_count()
allocate(args(num_args)) ! I've omitted checking the return status of the allocation
do ix = 1, num_args
call get_command_argument(ix,args(ix))
! now parse the argument as you wish
end do
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
Note:
The second argument to the subroutine get_command_argument is a character variable which you'll have to parse to turn into a real (or whatever). Note also that I've allowed only 12 characters in each element of the args array, you may want to fiddle around with that.
As you've already figured out read isn't used for reading command line arguments in Fortran programs.
Since you want to read an array of real numbers, you might be better off using the approach you've already figured out, that is reading them from the terminal after the program has started, it's up to you.
The easiest way is to use a library. There is FLAP or f90getopt available. Both are open source and licensed under free licenses.
The latter is written by Mark Gates and me, just one module and can be learned in minutes but contains all what is needed to parse GNU- and POSIX-like command-line options. The first is more sophisticated and can be used even in closed-source projects. Check them out.
Furthermore libraries at https://fortranwiki.org/fortran/show/Command-line+arguments
What READ (*,*) does is that it reads from the standard input. For example, the characters entered using the keyboard.
As the question shows COMMAND_ARGUMENT_COUNT() can be used to get the number of the command line arguments.
The accepted answer by High Performance Mark show how to retrieve the individual command line arguments separated by blanks as individual character strings using GET_COMMAND_ARGUMENT(). One can also get the whole command line using GET_COMMAND(). One then has to somehow parse that character-based information into the data in your program.
I very simple cases you just need the program requires, for example, two numbers, so you read one number from arg 1 and another form arg 2. That is simple. Or you can read a triplet of numbers from a single argument if they are comma-separated like 1,2,3 using a simple read(arg,*) nums(1:3).
For general complicated command line parsing one uses libraries such as those mentioned in the answer by Hani. You have set them up so that the library knows the expected syntax of the command line arguments and the data it should fill with the values.
There is a middle ground, that is still relatively simple, but one already have multiple arguments, that correspond to Fortran variables in the program, that may or may not be present. In that case one can use the namelist for the syntax and for the parsing.
Here is an example, the man point is the namelist /cmd/ name, point, flag:
implicit none
real :: point(3)
logical :: flag
character(256) :: name
character(1024) :: command_line
call read_command_line
call parse_command_line
print *, point
print *, "'",trim(name),"'"
print *, flag
contains
subroutine read_command_line
integer :: exenamelength
integer :: io, io2
command_line = ""
call get_command(command = command_line,status = io)
if (io==0) then
call get_command_argument(0,length = exenamelength,status = io2)
if (io2==0) then
command_line = "&cmd "//adjustl(trim(command_line(exenamelength+1:)))//" /"
else
command_line = "&cmd "//adjustl(trim(command_line))//" /"
end if
else
write(*,*) io,"Error getting command line."
end if
end subroutine
subroutine parse_command_line
character(256) :: msg
namelist /cmd/ name, point, flag
integer :: io
if (len_trim(command_line)>0) then
msg = ''
read(command_line,nml = cmd,iostat = io,iomsg = msg)
if (io/=0) then
error stop "Error parsing the command line or cmd.conf " // msg
end if
end if
end subroutine
end
Usage in bash:
> ./command flag=T name=\"data.txt\" point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
or
> ./command flag=T name='"data.txt"' point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
Escaping the quotes for the string is unfortunately necessary, because bash eats the first quotes.

Displaying List of AutoHotkey Hotkeys

I’ve written script that contains numerous hotkeys (general structure is as below). I would like to create another one that when pressed displays a list of all of the hotkeys and their corresponding descriptions that the script contains in a nice, formatted table.
The formatting and display are tenuous since AutoHotkey’s output is limited to message-boxes, but possible. More problematic is getting the hotkeys and corresponding descriptions.
The hotkeys all call the same function with different arguments. I considered adding a variable to the function so that depending on the value, the function either performs the normal function when triggered by the normal hotkeys, or builds a string or something when triggered from the special display hotkey.
I cannot figure out a way to programmatically access the script’s hotkeys at all. I checked the docs and there don’t seem to be any A_ variables that can be used for this purpose, nor does the Hotkey command lend itself well (it can be used to test if a hotkey exists, but looping through the innumerable combinations is, at best, tedious).
Failed attempts:
I tried using Elliot’s suggestion of parsing the script itself (replacing the path with %A_ScriptFullPath%, and while it does work for a raw script, it does not when the script is compiled
I tried assigning the entire hotkey section of the script to a variable as a continuation section and then parsing the variable and creating hotkeys using the Hotkey command. This worked well right up until the last part because the Hotkey command cannot take arbitrary commands as the destination and requires existing labels.
The ListHotkeys command is not applicable because it only displays the hotkeys as plain text in the control window.
Does anyone know how I can display a list of the hotkeys and either their corresponding arguments or comments?
Example script:
SomeFunc(foobar)
{
MsgBox %foobar%
}
!^#A::SomeFunc("a") ; blah
^+NumpadMult::SomeFunc("c") ; blivet
^+!#`::SomeFunc("b") ; baz
^#Space::SomeFunc("d") ; ermahgerd
…
Example desired “outputs”:
C+A+ W+ A a | C+ S+ NumpadMult b
------------------+----------------------
C+A+S+W+ ` c | C+ W+ Space d
    or
Ctrl Alt Shift Win Key Action
-----------------------------------------
× × × A blah
× × NumpadMult baz
× × × × ` blivet
× × Space ermahgerd
etc.
The only thing I can think of is to read each line of your script individually and parse it. This code reads your script (script.ahk) one line at a time and parses it. This should get you started. Additionally, you could parse the line to check for the modifiers as well.
Loop
{
FileReadLine, line, C:\script.ahk, %A_Index%
if ErrorLevel
break
If Instr(line, "::")
{
StringSplit, linearray, line, ::,
key := linearray1
StringSplit, commandarray, linearray3, `;
action := commandarray2
hotkeyline := "key: " . key . "`tAction: " . action
final .= hotkeyline . "`r"
}
}
msgbox % final
return
I found a solution. It is not perfect (or ideal), and hopefully a proper, built-in method will become available in the future, but it works well (enough) and for raw and compiled scripts.
What I did was to use the FileInstall command which tells the compiler to add a file to the executable (and extract it when run).
Sadly, the FileInstall command will not allow the use of variables for the source file, so I cannot simply include the script itself (FileInstall, %A_ScriptFullPath%, %A_Temp%\%A_ScriptName%, 1).
As a work-around, I ended up extracting all of the desired hotkeys to a second file which I then parse as Elliot suggested, then delete, and #Include at the end of my script (it must be at the end since hotkeys will terminate the autoexecute section).
;;;;; Test.ahk ;;;;;
; Add hotkey file to executable and extract to Temp directory at runtime
FileInstall, Hotkeys.ahk, %A_Temp%\Hotkeys.ahk, 1
Loop
{
;Read a line from the extracted hotkey script and quit if error
FileReadLine, line, %A_Temp%\Hotkeys.ahk, %A_Index%
if ErrorLevel
break
;Trim whitespace
line=%line%
; Parse the line as in Elliot’s answer, but with tweaks as necessary
ParseHotkey(line)
…
}
FileDelete, %A_Temp%\Hotkeys.ahk ; Delete the extracted script
DisplayHotkeys() ; I ended up bulding and using a GUI instead
#Include, Hotkeys.ahk ; It is included at compile-time, so no A_Temp
;;;;; Hotkeys.ahk ;;;;;
z::MsgBox foo
y::MsgBox bar