Autohotkey - how to store unicode and use it? - unicode

Here's my code below. AHK file is saved as UTF-8 with BOM and I can see the unicode characters just fine whenever I paste it into the script. But everytime I save the script and re-open it, the unicode characters become question marks and random gibberish characters. When "sendinput" is run, the output also comes out as question marks and gibberish, instead of the actual unicode emoticons.
MyVarEmoticon =
(Ltrim
What is your choice? (Enter #):
1. (╯°□°)╯︵ ┻━┻
2. (┛ಠ_ಠ)┛彡┻━┻
3. (╯°Д°)╯︵/(.□ . \)
4. ┏━┓┏━┓┏━┓ ︵ /(^.^/)
)
InputBox, MyVarEmoticonChoices, Emoticon Choices, %MyVarEmoticon%, , 400, % HEmoticon(MyVarEmoticon),,,,,1
HEmoticon(MyVarEmoticon)
{
StringReplace, MyVarEmoticon,myvaremoticon,`n,`n,UseErrorLevel
Lines:=ErrorLevel+1
height:=lines * 30 ; play with this value !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;MsgBox % height
If (Height < 40) ; too low
Height+=80
Return height
}
if ErrorLevel {
;MsgBox, CANCEL was pressed.
} else {
if (MyVarEmoticonChoices = "1"){
MyVarEmoticonChoices = (╯°□°)╯︵ ┻━┻
}
if (MyVarEmoticonChoices = "2"){
MyVarEmoticonChoices = (┛ಠ_ಠ)┛彡┻━┻
}
if (MyVarEmoticonChoices = "3"){
MyVarEmoticonChoices = (╯°Д°)╯︵/(.□ . \)
}
if (MyVarEmoticonChoices = "4"){
MyVarEmoticonChoices = ┏━┓┏━┓┏━┓ ︵ /(^.^/)
}
WinGetPos, X, Y, Width, Height, ahk_exe ToW.exe, , ,
XVar = %X%
YVar = %Y%
WVar = %Width%
HVar = %Height%
XWVar = % XVar+39
YHVar = % YVar+682
Sleep,200
sendinput, {raw}%MyVarEmoticonChoices%

Although there are some quite weird things in this code, it seems to work as expected if saved with the correct encoding.
I can't really know what goes wrong when you're trying to save it, maybe try to explain the steps you take to save it in the editor you're using.
If you don't want to worry about file encoding, you could store the characters as code points for example.
You can find a quick little converter with a Google search, here is the one I landed on with a Google search:
http://unicode.scarfboy.com/?s=%28%E2%95%AF%C2%B0%E2%96%A1%C2%B0%29%E2%95%AF%EF%B8%B5+%E2%94%BB%E2%94%81%E2%94%BB
And then you can convert to the code points to characters with Chr().
For example:
emote := "0028 256F 00B0 25A1 00B0 0029 256F FE35 0020 253B 2501 253B"
for each, codepoint in StrSplit(emote, " ")
output .= Chr("0x" codepoint)
Clipboard := output
SendInput, ^v
And here I'm also utilizing the clipboard and sending Ctrl+v, which is a good trick if you can use it. Especially for long text, which this really isn't I guess, but I figured I'd show it.
Or if you want to Send the string, you can use the Unicode notation:
emote := "0028 256F 00B0 25A1 00B0 0029 256F FE35 0020 253B 2501 253B"
for each, codepoint in StrSplit(emote, " ")
output .= "{U+" codepoint "}"
SendInput, % output
;SendInput, % "{U+0028}{U+256F}{U+00B0}{U+25A1}{U+00B0}{U+0029}{U+256F}{U+FE35}{U+0020}{U+253B}{U+2501}{U+253B}"

In ahk script files you must choose UTF-16 LE BOM Encoding to support Unicode characters. That's a Microsoft Windows default behaviour which indicates all other encodings as ASCII.

Related

Replacement of text in xml file by AHK - get error when trying to open as xml file

I am using an AHK script to replace some text in an .xml file (Result.xml in this case). The script then saves a file as Result_copy.xml. It changes exactly what I need, but when I try to open the new xml file, it won't open, giving me the error:
This page contains the following errors:
error on line 4 at column 16: Encoding error
Below is a rendering of the page up to the first error.
I only replaced text at line 38 using:
#Include TF.ahk
path = %1%
text = %2%
TF_ReplaceLine(path, 38, 38, text)
%1% and %2% are given by another program and are working as should
I also see that the orginal Result.xml is 123 kb and Result_copy.xml is 62 kb, even though I only add text. When I take Result.xml and manually add the text and save it, it's 123 kb and still opens. so now both files contain exactly the same Characters, but one won't open as xml. I think that something happens during saving/copying, which I don't understand.
Could someone help me out on this one? I don't have a lot of experience in AHK scripting and do not have a programming background.
Thank you in advance!
Michel
TF.ahk contains this:
/*
Name : TF: Textfile & String Library for AutoHotkey
Version : 3.8
Documentation : https://github.com/hi5/TF
AutoHotkey.com: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=576
AutoHotkey.com: http://www.autohotkey.com/forum/topic46195.html (Also for examples)
License : see license.txt (GPL 2.0)
Credits & History: See documentation at GH above.
TF_ReplaceLine(Text, StartLine = 1, Endline = 0, ReplaceText = "")
{
TF_GetData(OW, Text, FileName)
TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList
Loop, Parse, Text, `n, `r
{
If A_Index in %TF_MatchList%
Output .= ReplaceText "`n"
Else
Output .= A_LoopField "`n"
}
Return TF_ReturnOutPut(OW, OutPut, FileName)
}

How to check what the first word in clipboard is?

Lets say my Cliboard variable is currently in this state:
Clipboard:= "-Classes Essay on Hobbes
I want to perform If conditions depending on the first block/word in the clipboard, in this case -Classes . Essentially doing something like below using FileAppend:
if "-diary"{
;Create file in /Diary/Entry 27.MD
}
Else if "-Classes"{
;Create file in /Classes/Essay on Hobbes.MD
}
I was able to find this page in the docs If Var in/contains MatchList - Syntax & Usage | AutoHotkey but its not positional, which means if the block -Classes is also present as part of the file name for some reason, my logic breaks.
I have taken the liberty to crosspost this question on other forums as well.
Any help would be greatly appreciated!
Or.. you can just:
Clipboard:= "-Classes Essay on Hobbes"
Gosub % subroutine := SubStr( Clipboard, 1, InStr( Clipboard, " " )-1 )
Clipboard:= "-diary diary example"
Gosub % subroutine := SubStr( Clipboard, 1, InStr( Clipboard, " " )-1 )
Return
-diary:
MsgBox % "Diary:`n" StrReplace( clipboard, subroutine " " )
;Create file in /Diary/Entry 27.MD
Return
-Classes:
MsgBox % "Classes:`n" StrReplace( clipboard, subroutine " " )
;Create file in /Classes/Essay on Hobbes.MD
Return
You might try StrSplit()
; Array := StrSplit(String , Delimiters, OmitChars, MaxParts)
clip_array := StrSplit(Clipboard, A_Space, , 1)
if clip_array[1] = "-diary"{
;Create file in /Diary/Entry 27.MD
}
Else if clip_array[1] = "-Classes"{
;Create file in /Classes/Essay on Hobbes.MD
}
Else {
MsgBox % "No match for " clip_array[1]
}
Described here https://www.autohotkey.com/docs/commands/StrSplit.htm and note the param for MaxParts which addresses how many "tokens" to look in to (keeping the rest in the last) if the clipboard is sufficiently large to matter (in which case I'm not sure any of the other answers address any better).
If the amount of text on the clipboard is enormous, that could cause lagging with the script loading all of that text into the script memory, just to check the first value. I'd recommend regexMatch since that can return a position and capture the word as well without parsing everything.
; for reference of regexMatch function
; regexMatch(Haystack, Needle, outputVar, startPos)
Fnd := regexMatch(Clipboard, "U)(\-[\w]+))", capSubStr, inStr(Clipboard, "-"))
if (Fnd==0) {
Msgbox, Didn't find a word on the Clipboard.
Return
}
checkVal := capSubStr1
if (checkVal=="-diary") {
;Create file in /Diary/Entry 27.MD
} Else if (checkVal=="-Classes") {
;Create file in /Classes/Essay on Hobbes.MD
}
Here is the basic reference for using regular expressions with AHK: https://www.autohotkey.com/docs/misc/RegEx-QuickRef.htm
That will give an idea as to what the above expression is actually looking for, if you are not already familiar with regex.

Get First Character of A_LoopFileName?

I'm trying to parse a filename and get the first character from it as a string to compare it to a previously inputted variable. My code looks like:
FileSelectFolder, WhichFolder ; Ask the user to pick a folder.
; Ask what letter you want to start the loop from
InputBox, UserInput, Start At What Letter?, Please enter a letter to start at within the folder (CAPITALIZE IT!)., , 450, 150
if ErrorLevel {
MsgBox, CANCEL was pressed.
ExitApp
} else {
inputted_letter = %UserInput%
tooltip %inputted_letter% ; Show the inputted letter
sleep, 2000
tooltip
}
Loop, %WhichFolder%\*.*
{
current_filename_full = %A_LoopFileName%
files_first_letter := SubStr(current_filename_full, 1, 1)
tooltip %files_first_letter% ; Show the file's first letter
sleep, 2000
tooltip
if files_first_letter != inputted_letter
continue
...
Right now, it clearly shows in the tooltips the user-entered capital letter, and then the first letter of each file name from within the selected folder, but for some reason when the two look alike, it doesn't recognize them as a match. I'm thinking maybe because technically A_LoopFileName is not of a string type? Or maybe the inputted letter doesn't match the type of the first filename's letter?
I want it to continue if the inputted letter and the first letter of the filename don't match, but if they do, to carry on with the rest of the script. Any ideas on how I can get these two to successfully match? Thanks!
Firstly, AHK doesn't really have types. At least not how you've experienced types in other languages.
So your assumption about "not being correct type" will pretty much always be wrong.
So the actual cause is because in a legacy if statement, the syntax is
if <name of variable> <operator> <legacy way of representing a value>
So you'd do it like this:
if files_first_letter != %inputted_letter%
You we're comparing if the variable files_first_letter is equal to the literal text inputted_letter.
However, I highly recommend you stop using legacy syntax. It's really just that old.
It'll differ horribly much from any other programming language and you run into confusing behavior like this. Expression syntax is what you want to use in AHK nowadays.
Here's your code snippet converted over to expression syntax in case you're interested:
FileSelectFolder, WhichFolder
;Forcing an expression like this with % in every parameter
;is really not needed of course, and could be considered
;excessive, but I'm doing it for demonstrational
;purposes here. Putting everything in expression syntax.
;also, not gonna lie, I always do it myself haha
InputBox, UserInput, % "Start At What Letter?", % "Please enter a letter to start at within the folder (CAPITALIZE IT!).", , 450, 150
if (ErrorLevel)
;braces indicate an expression and the non-legacy if statement
;more about this, as an expression, ErrorLevel here holds the value
;1, which gets evaluated to true, so we're doing
;if (true), which is true
{
MsgBox, % "CANCEL was pressed."
ExitApp
}
else
inputted_letter := UserInput ; = is never used, always :=
Loop, Files, % WhichFolder "\*.*"
;non-legacy file loop
;note that here forcing the expression statement
;with % is actually very much needed
{
current_filename_full := A_LoopFileName
files_first_letter := SubStr(current_filename_full, 1, 1)
if (files_first_letter != inputted_letter)
continue
}
Also you don't have to be concerned about case with !=, it'll always compare case insensitively.

Autohotkey foreign language accents

I'm trying to create an easy ahk script for sending letters with accent marks when typing in different languages.
I know I can use !a::Send {U+00E0} to send à, but is there an easy way to say "If I enter a capital a, send À? I thought I'd be able to use !+a::Send {U+00C0} but that doesn't seem to work (and also seems a bit more complicated than it should be)
Eabryt,
The way I addressed this in AutoHotKey is like this:
;===== SPECIAL CHARACTERS FOR US KEYBOARD DRIVER (NOT US INTERNATIONAL) =======
:?C*:`` :: ; Turn `{Space} into a neutral `, else ` will be used in next vowel.
Send, ``{Space}{BackSpace}
Return
:?C*:``a::à
:?C*:``i::ì
:?C*:``e::è
:?C*:``o::ò
:?C*:``u::ù
:?C*:``A::À
:?C*:``I::Ì
:?C*:``E::È
:?C*:``O::Ò
:?C*:``U::Ù
:?C*:^ :: ; Turn ^{Space} into neutral ^, else ^ will be used in next vowel.
Send, {^}{Space}{BackSpace}
Return
:?C*:^a::â
:?C*:^i::î
:?C*:^e::ê
:?C*:^o::ô
:?C*:^u::û
:?C*:^A::Â
:?C*:^I::Î
:?C*:^E::Ê
:?C*:^O::Ô
:?C*:^U::Û
:?C*:`" :: ; Turn "{Space} into neutral ", else " will be used in next vowel.
Send, +{'}{Space}{BackSpace}
Return
:?C*:`'a::ä ; I used 'because I use the Umlaut's much more often than the accent aigu
:?C*:`;a::ä
:?C*:`'i::ï
:?C*:`;i::ï
:?C*:`'e::ë
:?C*:`;e::ë
:?C*:`'o::ö
:?C*:`;o::ö
:?C*:`'u::ü
:?C*:`;u::ü
:?C*:`'A::Ä
:?C*:`'I::Ï
:?C*:`'E::Ë
:?C*:`'O::Ö
:?C*:`'U::Ü
:?C*:' :: ; Turn '{Space} into neutral ', else ' will be used in next vowel.
Send, {'}{Space}{BackSpace}
Return
:?C*:`"a::á
:?C*:`"i::í
:?C*:`"e::é
:?C*:`"o::ó
:?C*:`"u::ú
:?C*:`"A::Á
:?C*:`"I::Í
:?C*:`"E::É
:?C*:`"O::Ó
:?C*:`"U::Ú
:?C*:`'c::ç
:?C*:`'C::Ç
:?C*:ss]::ß
:?C*:sss::ß
:?C*:ae]::æ
:?C*:AE]::Æ
:?C*:oe]::œ
:?C*:OE]::Œ
I use the Umlauts far more often than the accent aigu, therefore I (personally) swapped the use of the "and ' on my US International Keyboard. If this is too confusing, then just swap:
:?C*:`'a::ä with :?C*:`"a::ä
and
:?C*:`"a::á with :?C*:`'a::á
At the end are some special characters. I use the ] as the end sign for these special characters as it is close to the [Enter] key.

How to convert Unicode characters to escape codes

So, I have a bunch of strings like this: {\b\cf12 よろてそ } . I'm thinking I could iterate over each character and replace any unicode (Edit: Anything where AscW(char) > 127 or < 0) with a unicode escape code (\u###). However, I'm not sure how to programmatically do so. Any suggestions?
Clarification:
I have a string like {\b\cf12 よろてそ } and I want a string like {\b\cf12 [STUFF]}, where [STUFF] will display as よろてそ when I view the rtf text.
You can simply use the AscW() function to get the correct value:-
sRTF = "\u" & CStr(AscW(char))
Note unlike other escapes for unicode, RTF uses the decimal signed short int (2 bytes) representation for a unicode character. Which makes the conversion in VB6 really quite easy.
Edit
As MarkJ points out in a comment you would only do this for characters outside of 0-127 but then you would also need to give some other characters inside the 0-127 range special handling as well.
Another more roundabout way, would be to add the MSScript.OCX to the project and interface with VBScript's Escape function. For example
Sub main()
Dim s As String
s = ChrW$(&H3088) & ChrW$(&H308D) & ChrW$(&H3066) & ChrW$(&H305D)
Debug.Print MyEscape(s)
End Sub
Function MyEscape(s As String) As String
Dim scr As Object
Set scr = CreateObject("MSScriptControl.ScriptControl")
scr.Language = "VBScript"
scr.Reset
MyEscape = scr.eval("escape(" & dq(s) & ")")
End Function
Function dq(s)
dq = Chr$(34) & s & Chr$(34)
End Function
The Main routine passes in the original Japanese characters and the debug output says:
%u3088%u308D%u3066%u305D
HTH