Autohotkey script - hotstring prevents if statement from working - if-statement

:*:pl::pleaseHelpMe ; hotstring
:*:rf::reallyConfused ; hotstring
toggle := 0
\::
if (toggle = 0)
{
Run "https://www.google.com.sg/"
}
return
The code above does not work for the keystroke '\'
However, the code below works without the hotstrings
toggle := 0
\::
if (toggle = 0)
{
Run "https://www.google.com.sg/"
}
return
Why is that so? And how do I circumvent it and have the use of my hotstrings and the keystroke '\' to open google. Thanks a billion!!

You cannot define a variable between hotkeys or hotstrings.
A variable has to be defined
in the auto executable section of the script (top of the script,
before the first return or hotkey),
or in a hotkey,
or in a function.
Example:
; top of the script:
toggle := 0
return ; end of auto-execute section
; toggling a variable:
F1:: toggle := !toggle ; Pressing F1 changes the value of the variable "toggle" between 1 (true) and 0 (false)
:*:pl::pleaseHelpMe ; hotstring
:*:rf::reallyConfused ; hotstring
\::
if (toggle) ; If the value of the variable "toggle" is 1 (true)
Run "https://www.google.com.sg/"
else
Send, \
return

user3419297 is wrong. AutoHotkey does not need to define a variable prior to it's use. If a variable isn't defined it is automatically given a value of False or 0 during an evaluation.
This code works, I only added $ option to the hotkey to prevent the hotkey from triggering itself:
; toggling a variable:
F1:: toggle := !toggle ; Pressing F1 changes the value of the variable "toggle" between 1 (true) and 0 (false)
:*:pl::pleaseHelpMe ; hotstring
:*:rf::reallyConfused ; hotstring
$\::
if (toggle) ; If the value of the variable "toggle" is 1 (true)
Run "https://www.google.com.sg/"
else
Send, \
return
esc::exitApp

Related

extra words after "else" clause in "if" command for TCL code

I have a tcl code where -
if { $xyz == 43 } {
# 1. Set some variables
set my_filename_log "somename_log.txt"
if {[file exists $my_filename_log ]} {
file delete -force $my_filename_log
}
} # end of xyz = 43
I am getting error as - TCLERROR: wrong # args: extra words after "else" clause in "if" command while compiling -
if { $xyz == 43 } {
# 1. Set some variables...
Not sure what is wrong with this code, checked tcl documentation didnt find anything
In Tcl, for else if condition should be written without space as elseif. Otherwise you will get the error you have mentioned.
if {$xyz==1} {
puts "Yes"
} else if {$xyz==2} {
puts "No"
}
wrong # args: extra words after "else" clause in "if" command
In your code, you have used
} # end of xyz = 43
at the last line. You have to use ; to mark the end of the statements and then you can start the comments with #.
So, your code should be written as,
if { $xyz == 43 } {
# 1. Set some variables
set my_filename_log "somename_log.txt"
if {[file exists $my_filename_log ]} {
file delete -force $my_filename_log
}
}; # end of xyz = 43

AHK - How to use dynamic hotstring with a barcode scanner

I need to trigger a subroutine when a serial number of a product has been scanned in with a barcode scanner. The serial number looks like this: 11NNNN22334. I then need to use the scanned in serial number as a variable.
I tried dynamic regular expression hotstrings library which I include below, but I can't make it work reliably using a barcode scanner (it's too fast). I don't want to slow down the barcode scanner. It either does not trigger the subroutine at all or leaves the first digit of the serial number behind after the subroutine been triggered. Any ideas?
Test:
MsgBox, %$1% ; THIS IS THE STRING THAT TRIGGERED THE SUBROUTINE
return
hotstrings("([0-9][0-9]NNNN[0-9][0-9][0-9][0-9][0-9])", "Test")
/*
Function: HotStrings
Dynamically adds regular expression hotstrings.
Parameters:
c - regular expression hotstring
a - (optional) text to replace hotstring with or a label to goto,
leave blank to remove hotstring definition from triggering an action
Examples:
> hotstrings("(B|b)tw\s", "%$1%y the way") ; type 'btw' followed by space, tab or return
> hotstrings("i)omg", "oh my god!") ; type 'OMG' in any case, upper, lower or mixed
> hotstrings("\bcolou?r", "rgb(128, 255, 0);") ; '\b' prevents matching with anything before the word, e.g. 'multicololoured'
License:
- RegEx Dynamic Hotstrings: Modified version by Edd
- Original: <http://www.autohotkey.net/~polyethene/#hotstrings>
- Dedicated to the public domain (CC0 1.0) <http://creativecommons.org/publicdomain/zero/1.0/>
*/
hotstrings(k, a = "", Options:="")
{
static z, m = "~$", m_ = "*~$", s, t, w = 2000, sd, d = "Left,Right,Up,Down,Home,End,RButton,LButton", f = "!,+,^,#", f_="{,}"
global $
If z = ; init
{
RegRead, sd, HKCU, Control Panel\International, sDecimal
Loop, 94
{
c := Chr(A_Index + 32)
If A_Index between 33 and 58
Hotkey, %m_%%c%, __hs
else If A_Index not between 65 and 90
Hotkey, %m%%c%, __hs
}
e = 0,1,2,3,4,5,6,7,8,9,Dot,Div,Mult,Add,Sub,Enter
Loop, Parse, e, `,
Hotkey, %m%Numpad%A_LoopField%, __hs
e = BS,Shift,Space,Enter,Return,Tab,%d%
Loop, Parse, e, `,
Hotkey, %m%%A_LoopField%, __hs
z = 1
}
If (a == "" and k == "") ; poll
{
q:=RegExReplace(A_ThisHotkey, "\*\~\$(.*)", "$1")
q:=RegExReplace(q, "\~\$(.*)", "$1")
If q = BS
{
If (SubStr(s, 0) != "}")
StringTrimRight, s, s, 1
}
Else If q in %d%
s =
Else
{
If q = Shift
return
Else If q = Space
q := " "
Else If q = Tab
q := "`t"
Else If q in Enter,Return,NumpadEnter
q := "`n"
Else If (RegExMatch(q, "Numpad(.+)", n))
{
q := n1 == "Div" ? "/" : n1 == "Mult" ? "*" : n1 == "Add" ? "+" : n1 == "Sub" ? "-" : n1 == "Dot" ? sd : ""
If n1 is digit
q = %n1%
}
Else If (GetKeyState("Shift") ^ !GetKeyState("CapsLock", "T"))
StringLower, q, q
s .= q
}
Loop, Parse, t, `n ; check
{
StringSplit, x, A_LoopField, `r
If (RegExMatch(s, x1 . "$", $)) ; match
{
StringLen, l, $
StringTrimRight, s, s, l
if !(x3~="i)\bNB\b") ; if No Backspce "NB"
SendInput, {BS %l%}
If (IsLabel(x2))
Gosub, %x2%
Else
{
Transform, x0, Deref, %x2%
Loop, Parse, f_, `,
StringReplace, x0, x0, %A_LoopField%, ¥%A_LoopField%¥, All
Loop, Parse, f_, `,
StringReplace, x0, x0, ¥%A_LoopField%¥, {%A_LoopField%}, All
Loop, Parse, f, `,
StringReplace, x0, x0, %A_LoopField%, {%A_LoopField%}, All
SendInput, %x0%
}
}
}
If (StrLen(s) > w)
StringTrimLeft, s, s, w // 2
}
Else ; assert
{
StringReplace, k, k, `n, \n, All ; normalize
StringReplace, k, k, `r, \r, All
Loop, Parse, t, `n
{
l = %A_LoopField%
If (SubStr(l, 1, InStr(l, "`r") - 1) == k)
StringReplace, t, t, `n%l%
}
If a !=
t = %t%`n%k%`r%a%`r%Options%
}
Return
__hs: ; event
hotstrings("", "", Options)
Return
}
You can try to speed up the hotkeys function by fiddling with SetBatchLines:
hotstrings(k, a = "", Options:="")
{
prevBatchlines := A_BatchLines
SetBatchLines, -1
... ; rest of function here
}
; reset to whatever it was
SetBatchLines, %prevBatchlines%
Return
__hs: ; event
hotstrings("", "", Options)
Return
}
Although usually not recommended (it's nonzero by default for a reason), sometimes it is the only way.
Maybe give this a shot, it's setup to wait for your required syntax:
code:=
for k, v in StrSplit("QWERTYUIOPASDFGHJKLZXCVBNM")
Hotkey, % "~" v, WaitForBarcode
Loop 10 {
Hotkey, % "~" (10-A_Index) "", WaitForBarcode
Hotkey, % "~Numpad" (10-A_Index) "", WaitForBarcode
}
return
FoundCode(var) {
MsgBox % "Caught code: " var
}
WaitForBarcode(){
global code
k:=SubStr(A_ThisHotkey,0)
code.=k
code:=(is(SubStr(code,1,2))=1)?k:(is(SubStr(code,3,4))=2)?k:(is(SubStr(code,7,5))=1)?k:(StrLen(code)=11)?FoundCode(code):code
}
is(var) {
if var is not digit
return 1
if var is not alpha
return 2
}
I have no way of testing it with any input device other than keyboard, maybe it will work, maybe not.
Alternative for looping through keys would be:
Loop 43
Hotkey, % "~" Chr(A_Index+47), Bar
At work we have a lot of USB barcode scanners that type the scan results to the keyboard buffer.
If you have access to the barcode scanner and it's a hardware scanner,
you usually can definde a prefix/postfix code the scanner has to send before the scan. Check your scanner manual, to set it you normally just scan a few barcodes.
If you define the prefix code as a hotkey you can then run code to capture the letters until the post fix.
A simple example on key capture is
Loop {
Input, key, I L1 V
log = %log%%key%
}
#s::MsgBox, 64, Key History, %log%
It should be easy to change this to stop looping after the postfix key of your choice.
source here
Although it's not a solution, I managed to find a workaround by changing the scanner's suffix from carriage return to tab and using the original method I posted.

How to check if a string is empty

I need to check if a string (user input on an entry box) is empty or not and do some action based on that condition once I push the "Play" button.
This is my script:
entry .eInput -width 50 -relief sunken -justify center -textvariable Input
button .bAction -text "Play" -width 30 -height 5 -activebackground green -font "-12"
bind .bAction <1> {
if {$Input ne ""}
{ puts "string is not empty"}
else { puts "string is empty"}
}
But when I push the "Play" button this is the error:
wrong # args: no script following "$Input ne """ argument
wrong # args: no script following "$Input ne """ argument
while executing
"if {$Input ne ""}"
(command bound to event)
Any idea on how to fix it?
The problem is that you don't pass enough arguments to if
if {$Input ne ""}
Is not valid. In Tcl commands end with a newline.
Try to use
if {$Input ne ""} then {
puts "string is not empty"
} else {
puts "string is empty"
}

If Else-if in Robot Framework

I want get value from a Keyword by using else if.
Example:
String text = ""
If variable > 5
text = "one";
else if variable <5
text = "two";
else
text = "three";
In Robot Framework
I use the code
${txt} Set Variable
${txt}= Run Keyword If ${length} > 5 Some Keyword
\ ELSE IF ${length} < 5 Some Keyword
\ ELSE Some Keyword
Log ${txt}
ERROR !!!
In Keyword ELSE IF ; Keyword name cannot be empty
Just add THREE DOTS (...) in first cell before ELSE IF keyword
${txt} Set Variable
${txt}= Run Keyword If ${lenght} > 5 Some Keyword
... ELSE IF ${lenght} < 5 Some Keyword
... ELSE Some Keyword
Log ${txt}
An alternate way to code this with Robot Framework's version of a switch statement is:
*** Variables ***
String ${text} = ""
*** Keywords ***
${text} = Set Variable If
... ${variable} > 5 one
... ${variable} < 5 two
... ${variable} = 5 three
There may be other ways using Run Keyword If and Run Keyword Unless.
Since since robot 4.0, native IF else support is available. You can refer below example:
IF '${status}' == 'true'
${i} Set Variable 10
log to console inside if
ELSE IF '${status}' == 'false'
${i} Set Variable 20
log to console inside else if
ELSE
${i} Set Variable 30
log to console inside else
END

awk: process input from pipe, insert result before pattern in output file

I am trying to process an input stream through a simple awk function, and insert the results before an anchor pattern in an existing file. My function works fine, but I can't convince awk to write the results where and how I want them. The input is being piped as XML from hunspell to my script, which accepts as an argument the output file.
hunspell -L -H ./text.xml | ./parse.awk ./output.xml
#!/usr/bin/awk -f
#
function buildObjs()
{
a["x"]=$4*mils; a["y"]=-$5*mils; a["w"]=$6*mils; a["h"]=$7*mils
print "## element" NR+1 " [x]="a["x"]" [y]="a["y"]" [width]="a["w"]" [height]="a["h"]
print "set fsize("NR+1") {FALSE}"
print "set fmargin("NR+1") {FALSE}"
print "set fmaster("NR+1") {TRUE}"
print "set ftype("NR+1") {box}"
print "set fname("NR+1") {"a["w"],a["h"]"}"
print "set fatt("NR+1") {1}"
print "set dplObjectSetup("NR+1",TRA) {"a["x"],a["y"]"}"
print "set fnum("NR+1") {}"
return 0
}
BEGIN {
FS = "[\" ]+"
mils = "0.3527"
for (i = 0; i < ARGC; i++) {
# Use this block to identify the output file we need to write to.
if (ARGV[i] ~ /output.+/) {
outFile=ARGV[i]
delete ARGV[i]
}
}
while ((getline line < outFile) > 0) {
if (line ~ !/set lineno \{.+\}/) {
print line
}
}
close(outFile)
}
{
buildObjs()
}
END {
print "set lineno {"NR+2"}"
while ((getline line < outFile) > 0) {
if (line ~ /set mode \{.+\}/) {
print line
} else
print line
}
close(outFile)
}
The anchor pattern I'm looking for in the outFile is "set lineno {3}". In the stream from text.xml, there are 20 lines, and the buildObjs function loops on every line of input, meaning I'm defining 20 objects in the output file, iterating the object count with NR+1 as I go. The number of lines to be processed will vary from job to job. As a bonus question, the anchor pattern needs to be updated so that "set lineno {3}" becomes "set lineno {NR+2}" with whatever NR+2 resolves to for that job. Presumably I will do this in the END block, but right now I just need to get my new objects into the output file.
So in summary, stream input into my awk script, process it with my function, insert the result before a pattern in an existing file, update the anchor pattern and close the modified file. This is my first substantial use of awk outside of one-liners embedded in bash scripts. Any help is most appreciated.
EDIT: I've updated the code to reflect comments from Jonathan.
EDIT2: Updated the END block. This code now does what I want.
EDIT3: Here are a few lines being piped into my script:
<w box="45.2044 92.54 61.5253 9.503" xoffset="6.27627 12.6244 19.4125 25.5994 32.2113 38.159 48.5253">Technews</w>
<w box="407.31 91.6 107.774 10.443" xoffset="1.8024 6.7944 12.1711 18.8203 29.2284 36.5576 43.2034 50.0661 56.641 61.0251 68.0434 74.6553 85.0634 92.0651 97.1957 100.274">Issue256:June27th</w>
<w box="67.923 132.463 32.747 7.337" xoffset="6.259 14.168 19.129 21.747">DALIM</w>
An excerpt from the outFile:
# file.encoding: UTF-8
# sun.jnu.encoding: UTF-8
set toolVersion {1.20}
set ftype(0) {pgs}
set fsize(0) {FALSE}
set fmargin(0) {FALSE}
set fsize(1) {TRUE}
set fmargin(1) {TRUE}
set fmaster(1) {FALSE}
set ftype(1) {pgs}
set fname(1) {}
set fatt(1) {0}
set dplObjectSetup(1,TRA) {}
set fnum(1) {}
>> New data inserted here.
set lineno {2} << This number updated to reflect the total number of objects.
set mode {1}
set preservePDF {1}
set preservePDFAction {Continue}
So, as I hope this clarifies, after processing the piped input, I'm inserting additional blocks starting with "set fsize()" and ending with "set fnum()", incrementing as I go, and summing the total number of blocks in "set lineno {}" before finally appending the trailing lines after "set lineno {}".
Here's a modified version of your executable awk script that produces the ordering you want:
#!/usr/bin/awk -f
BEGIN { FS="[{}]"; mils="0.3527"; built=1 }
FNR==NR {
if( $1 !~ /set lineno/ ) {
if( lineno != "" ) { footer[++cnt]=$0; if(cnt==3) { FS = "[\" ]+" } }
else print
}
else { lineno=$2 }
next
}
FNR!=NR && NF > 0 { built += buildObjs( built+1 ) }
END {
print "set lineno {" built "}"
for(i=1;i<=cnt;i++ ) {
print footer[i]
}
}
function buildObjs( n )
{
x=$4*mils; y=-$5*mils; w=$6*mils; h=$7*mils
print "## element" n " [x]=" x " [y]=" y " [width]=" w " [height]=" h
print "set fsize(" n ") {FALSE}"
print "set fmargin(" n ") {FALSE}"
print "set fmaster(" n ") {TRUE}"
print "set ftype(" n ") {box}"
print "set fname(" n ") {" w " " h "}"
print "set fatt(" n ") {1}"
print "set dplObjectSetup(" n ",TRA) {" x " " y "}"
print "set fnum(" n ") {}"
return 1
}
When put into a file called awko it would be run like:
hunspell -L -H ./text.xml | ./awko ./output.xml -
I don't have hunspell installed, so I tested this by running the Edit3 piped output from a file via cat:
cat ./pipeddata | ./awko ./output.xml -
Notice the - at after the output file. It's telling awk to read from stdin as the 2nd input to the awk script, which lets me deal with the first file with the standard FNR==NR { do stuff; next } logic.
Here's the breakdown:
For personal preferences, I moved the buildObjs() function to the end of the script. Notice I added a n argument to it - NR won't be used in the output. I dropped the a array because it didn't seem to be necessary and changed it's return from 0 to 1.
In the BEGIN block, setup output.xml file parsing, and mils
Whenever the FILENAME changes to -, change FS for parsing that input. The piped data FS could instead be set on the command line between the output file and the -.
When FNR==NR handle the first file
Basically, print the "header" info when your anchor hasn't been read
When the anchor is read, store it's value in lineno
After the anchor is read, store the last of the output file into the footer array in cnt order. Knowing there are only 3 lines at the end, I "cheated" to adjust the FS before the first record is read from STDIN.
When FNR!=NR and the line isn't blank (NF>0), process the piped input, incrementing built and passing it with a offset of 1 as an arg to buildObjs() ( as built starts with a value of 0 ).
In the END, the set lineno line is reconstructed/printed with the sum of lineno and built.
Then the footer from the first file is printed in order based on the cnt variable
Using the cat form, I get following:
# file.encoding: UTF-8
# sun.jnu.encoding: UTF-8
set toolVersion {1.20}
set ftype(0) {pgs}
set fsize(0) {FALSE}
set fmargin(0) {FALSE}
set fsize(1) {TRUE}
set fmargin(1) {TRUE}
set fmaster(1) {FALSE}
set ftype(1) {pgs}
set fname(1) {}
set fatt(1) {0}
set dplObjectSetup(1,TRA) {}
set fnum(1) {}
## element2 [x]=32.6389 [y]=-21.7 [width]=3.35171 [height]=0
set fsize(2) {FALSE}
set fmargin(2) {FALSE}
set fmaster(2) {TRUE}
set ftype(2) {box}
set fname(2) {3.35171 0}
set fatt(2) {1}
set dplObjectSetup(2,TRA) {32.6389 -21.7}
set fnum(2) {}
## element3 [x]=32.3073 [y]=-38.0119 [width]=3.68325 [height]=0
set fsize(3) {FALSE}
set fmargin(3) {FALSE}
set fmaster(3) {TRUE}
set ftype(3) {box}
set fname(3) {3.68325 0}
set fatt(3) {1}
set dplObjectSetup(3,TRA) {32.3073 -38.0119}
set fnum(3) {}
## element4 [x]=46.7197 [y]=-11.5499 [width]=2.58776 [height]=0
set fsize(4) {FALSE}
set fmargin(4) {FALSE}
set fmaster(4) {TRUE}
set ftype(4) {box}
set fname(4) {2.58776 0}
set fatt(4) {1}
set dplObjectSetup(4,TRA) {46.7197 -11.5499}
set fnum(4) {}
set lineno {4}
set mode {1}
set preservePDF {1}
set preservePDFAction {Continue}
Seems like your buildObj() function logic needs some attention to get things just the way you want (I suspect the indexes you've chosen need shifting).
The main action { buildObjs(); PROFIT??; } (for whatever PROFIT?? means) is acted on for each line since there is no pattern before it. You should add a pattern to recognize where you want the output added:
/set lineno \{3\}/ { buildObjs() }
{ print }
The first recognizes the pattern ({ is an awk regex metacharacter, so it must be escaped), and the second ensures that the line is printed after the output from buildObjs(). Reverse the lines if you want the set lineno {3} to come first, of course.