Tuesday, March 3, 2009

AHK - How to Make a Language Pack

This tutorial should help you understand how to create programs that support the use of language packs. A language pack is usually a module that can be added to a program that will translate that program to a different language. These modules usually contain little more than strings of text that are translated versions of the original text.

First, we need the functions for using a language pack. These are a couple of functions that I've created. Note they require AHK 1.0.48+.
; This is the only function that you need to call in order to 
; retrieve the text for your current language. The styntax is
; as follows:
; Lang(Loc, Label)
; Loc - The area where the string is used.
; Label - The label for the string.
; Note that the Loc and Label should remain the same for every
; language used. These are identifiers that let you insert the
; correct string where you want it.

Lang(Loc, Label) {
Global Lang
Return (IsFunc(F := "Lang_" Lang) && L := %F%(Loc "_" Label))
? Lang_Parse(L)
: "<String """ Loc "_" Label """ not found for """ Lang """>"
}


; This function is used internally in Lang(). It isn't necessary to
; have, but it is somewhat useful. What it does is simply allow you
; to insert variables into the string. For example, if you want to
; have a string that says 'I have %N% apples!', instead of having to
; split it into 'Lang("General","Have") . N . Lang("General","Apples")'
; you can simply use 'Lang("General","HaveApples")'. More information
; on how to insert variables into strings will be available later.

Lang_Parse(Str) {
Global
Local M,M1
While RegExMatch(Str, "[^\\]\$([^\$]+)\$", M)
Str := RegExReplace(Str,"\$" M1 "\$",%M1%)
Return % RegExReplace(Str,"\\\$","$")
}

Now for the next step: creating the "module" functions. First, you need to figure out how you're going to identify the language. Generally the best way to do this is by using the 2-3 letter language code. For example, english is "en", german/deutsch is "de", french is "fr" etc. etc. So the name of the function for english then would be "Lang_en". Here's how I set up my module functions. Note that you can do this more than one way, this is simply what worked for me. The only requirement is that it names variables uniformly and accepts a parameter containing the name of the variable to return.
Lang_en(Var) {
Static
If (!Init) {
Init = 1
General_HaveApples = I have $N$ apples!
}
Return L := %Var%
}
; And the deutsch version (same file)
Lang_de(Var) {
Static
If (!Init) {
Init = 1
General_HaveApples = Ich habe $N$ Äpfel!
}
Return L := %Var%
}

So now you have a basic language pack basically completed. Notice how you can include variables in strings in a similar manner to AHK itself, but instead of using "%VarName%", you use "$VarName$". To put a plain "$" in a string, simply escape it using a backslash ("\").
If you put all of these functions in your script, and have the var %Lang% set to "en", whenever you call 'Lang("General","HaveApples")' it will return "I have %N% apples!". If you change the value of %Lang% to "de", the same function call will return "Ich habe %N% Äpfel!". This even allows for the changing of languages while the script is still running.

The final script could look a little like this:
Lang = en
MsgBox % Lang("General","HaveApples")
Lang = de
MsgBox % Lang("General","HaveApples")
Return

Lang(Loc, Label) {
Global Lang
Return (IsFunc(F := "Lang_" Lang) && L := %F%(Loc "_" Label))
? Lang_Parse(L)
: "<String """ Loc "_" Label """ not found for """ Lang """>"
}
Lang_Parse(Str) {
Global
Local M,M1
While RegExMatch(Str, "[^\\]\$([^\$]+)\$", M)
Str := RegExReplace(Str,"\$" M1 "\$",%M1%)
Return % RegExReplace(Str,"\\\$","$")
}
Lang_en(Var) {
Static
If (!Init) {
Init = 1
General_HaveApples = I have $N$ apples!
}
Return L := %Var%
}
Lang_de(Var) {
Static
If (!Init) {
Init = 1
General_HaveApples = Ich habe $N$ Äpfel!
}
Return L := %Var%
}


A note about the module functions: They have assume-static set, and initiate all of the variable they contain the first time that particular module is called. This is the reason for the "if (!Init) {" and "Init = 1" lines. This isn't necessary, and can be changed along with the Lang_Parse() function in order to make this method compatible with AHK versions older than 1.0.48.

Friday, February 27, 2009

AHK - A New Auto-Clicker

This is a new 5-line autoclicker made possible with the release of AHK 1.0.48. Use Insert to toggle it on and off.
LButton::
While GetKeyState("LButton","P")
Send {LButton}
Return
Insert::Hotkey, LButton, Toggle

Thursday, February 19, 2009

AHK - Submit GUI with {Enter}

This is an example of how you can use a hidden button control with the Default option set in order to submit a gui simply by pressing enter.
Gui, Add, Edit, vMyEdit
; Setting x and y prevents the button from changing the size
; of the GUI window when using autosize

Gui, Add, Button, Default Hidden x0 y0 gSubmit
Gui, Show, AutoSize
Return

Submit:
Gui, Submit
MsgBox Value in MyEdit was %MyEdit%
ExitApp


Forum Post

Sunday, January 25, 2009

AHK - On Screen Keyboard GUI

This is simply a pre-made GUI for an on screen keyboard (OSK).
; Download Files
If (!FileExist("border.jpg"))
UrlDownloadToFile, http://www.autohotkey.net/~Slanter/images/border.jpg, border.jpg
If (!FileExist("key.jpg"))
UrlDownloadToFile, http://www.autohotkey.net/~Slanter/images/key.jpg, key.jpg

; ----------
; Build OSK
; ----------
Gui, Color, FFFFFF
Gui, -Caption

; Border
Gui, Add, Pic, w650 h3 x0 y0, border.jpg
Gui, Add, Pic, w3 h238 x650 y0, border.jpg
Gui, Add, Pic, w3 h238 x0 y0, border.jpg
Gui, Add, Pic, w650 h3 x0 y235, border.jpg

; Row 1
Gui, Add, Pic, vKey_Esc w34 h34 xm+5 ym+5, key.jpg
Gui, Add, Pic, vKey_F1 w34 h34 xm+73 ym+5, key.jpg
Gui, Add, Pic, vKey_F2 w34 h34 xm+107 ym+5, key.jpg
Gui, Add, Pic, vKey_F3 w34 h34 xm+141 ym+5, key.jpg
Gui, Add, Pic, vKey_F4 w34 h34 xm+175 ym+5, key.jpg
Gui, Add, Pic, vKey_F5 w34 h34 xm+226 ym+5, key.jpg
Gui, Add, Pic, vKey_F6 w34 h34 xm+260 ym+5, key.jpg
Gui, Add, Pic, vKey_F7 w34 h34 xm+294 ym+5, key.jpg
Gui, Add, Pic, vKey_F8 w34 h34 xm+328 ym+5, key.jpg
Gui, Add, Pic, vKey_F9 w34 h34 xm+379 ym+5, key.jpg
Gui, Add, Pic, vKey_F10 w34 h34 xm+413 ym+5, key.jpg
Gui, Add, Pic, vKey_F11 w34 h34 xm+447 ym+5, key.jpg
Gui, Add, Pic, vKey_F12 w34 h34 xm+481 ym+5, key.jpg
Gui, Add, Pic, vKey_PrtScr w34 h34 xm+532 ym+5, key.jpg
Gui, Add, Pic, vKey_ScrlLk w34 h34 xm+566 ym+5, key.jpg
Gui, Add, Pic, vKey_Pause w34 h34 xm+600 ym+5, key.jpg

; Row 2
Gui, Add, Pic, vKey_Grave w34 h34 xm+5 ym+50, key.jpg
Gui, Add, Pic, vKey_N1 w34 h34 xm+39 ym+50, key.jpg
Gui, Add, Pic, vKey_N2 w34 h34 xm+73 ym+50, key.jpg
Gui, Add, Pic, vKey_N3 w34 h34 xm+107 ym+50, key.jpg
Gui, Add, Pic, vKey_N4 w34 h34 xm+141 ym+50, key.jpg
Gui, Add, Pic, vKey_N5 w34 h34 xm+175 ym+50, key.jpg
Gui, Add, Pic, vKey_N6 w34 h34 xm+209 ym+50, key.jpg
Gui, Add, Pic, vKey_N7 w34 h34 xm+243 ym+50, key.jpg
Gui, Add, Pic, vKey_N8 w34 h34 xm+277 ym+50, key.jpg
Gui, Add, Pic, vKey_N9 w34 h34 xm+311 ym+50, key.jpg
Gui, Add, Pic, vKey_N0 w34 h34 xm+345 ym+50, key.jpg
Gui, Add, Pic, vKey_Minus w34 h34 xm+379 ym+50, key.jpg
Gui, Add, Pic, vKey_Equals w34 h34 xm+413 ym+50, key.jpg
Gui, Add, Pic, vKey_Backspace w68 h34 xm+447 ym+50, key.jpg
Gui, Add, Pic, vKey_Insert w34 h34 xm+532 ym+50, key.jpg
Gui, Add, Pic, vKey_Home w34 h34 xm+566 ym+50, key.jpg
Gui, Add, Pic, vKey_PgUp w34 h34 xm+600 ym+50, key.jpg

; Row 3
Gui, Add, Pic, vKey_Tab w51 h34 xm+5 ym+84, key.jpg
Gui, Add, Pic, vKey_q w34 h34 xm+56 ym+84, key.jpg
Gui, Add, Pic, vKey_w w34 h34 xm+90 ym+84, key.jpg
Gui, Add, Pic, vKey_e w34 h34 xm+124 ym+84, key.jpg
Gui, Add, Pic, vKey_r w34 h34 xm+158 ym+84, key.jpg
Gui, Add, Pic, vKey_t w34 h34 xm+192 ym+84, key.jpg
Gui, Add, Pic, vKey_y w34 h34 xm+226 ym+84, key.jpg
Gui, Add, Pic, vKey_u w34 h34 xm+260 ym+84, key.jpg
Gui, Add, Pic, vKey_i w34 h34 xm+294 ym+84, key.jpg
Gui, Add, Pic, vKey_o w34 h34 xm+328 ym+84, key.jpg
Gui, Add, Pic, vKey_p w34 h34 xm+362 ym+84, key.jpg
Gui, Add, Pic, vKey_LB w34 h34 xm+396 ym+84, key.jpg
Gui, Add, Pic, vKey_RB w34 h34 xm+430 ym+84, key.jpg
Gui, Add, Pic, vKey_BS w51 h34 xm+464 ym+84, key.jpg
Gui, Add, Pic, vKey_Delete w34 h34 xm+532 ym+84, key.jpg
Gui, Add, Pic, vKey_End w34 h34 xm+566 ym+84, key.jpg
Gui, Add, Pic, vKey_PgDn w34 h34 xm+600 ym+84, key.jpg

; Row 4
Gui, Add, Pic, vKey_CapsLock w68 h34 xm+5 ym+118, key.jpg
Gui, Add, Pic, vKey_a w34 h34 xm+73 ym+118, key.jpg
Gui, Add, Pic, vKey_s w34 h34 xm+107 ym+118, key.jpg
Gui, Add, Pic, vKey_d w34 h34 xm+141 ym+118, key.jpg
Gui, Add, Pic, vKey_f w34 h34 xm+175 ym+118, key.jpg
Gui, Add, Pic, vKey_g w34 h34 xm+209 ym+118, key.jpg
Gui, Add, Pic, vKey_h w34 h34 xm+243 ym+118, key.jpg
Gui, Add, Pic, vKey_j w34 h34 xm+277 ym+118, key.jpg
Gui, Add, Pic, vKey_k w34 h34 xm+311 ym+118, key.jpg
Gui, Add, Pic, vKey_l w34 h34 xm+345 ym+118, key.jpg
Gui, Add, Pic, vKey_Colon w34 h34 xm+379 ym+118, key.jpg
Gui, Add, Pic, vKey_Quote w34 h34 xm+413 ym+118, key.jpg
Gui, Add, Pic, vKey_Return w68 h34 xm+447 ym+118, key.jpg

; Row 5
Gui, Add, Pic, vKey_LShift w85 h34 xm+5 ym+152, key.jpg
Gui, Add, Pic, vKey_z w34 h34 xm+90 ym+152, key.jpg
Gui, Add, Pic, vKey_x w34 h34 xm+124 ym+152, key.jpg
Gui, Add, Pic, vKey_c w34 h34 xm+158 ym+152, key.jpg
Gui, Add, Pic, vKey_v w34 h34 xm+192 ym+152, key.jpg
Gui, Add, Pic, vKey_b w34 h34 xm+226 ym+152, key.jpg
Gui, Add, Pic, vKey_n w34 h34 xm+260 ym+152, key.jpg
Gui, Add, Pic, vKey_m w34 h34 xm+294 ym+152, key.jpg
Gui, Add, Pic, vKey_Comma w34 h34 xm+328 ym+152, key.jpg
Gui, Add, Pic, vKey_Period w34 h34 xm+362 ym+152, key.jpg
Gui, Add, Pic, vKey_FS w34 h34 xm+396 ym+152, key.jpg
Gui, Add, Pic, vKey_RShift w85 h34 xm+430 ym+152, key.jpg
Gui, Add, Pic, vKey_UpArrow w34 h34 xm+566 ym+152, key.jpg

; Row 6
Gui, Add, Pic, vKey_LCtrl w43 h34 xm+5 ym+186, key.jpg
Gui, Add, Pic, vKey_LWin w42 h34 xm+48 ym+186, key.jpg
Gui, Add, Pic, vKey_LAlt w42 h34 xm+90 ym+186, key.jpg
Gui, Add, Pic, vKey_Space w214 h34 xm+132 ym+186, key.jpg
Gui, Add, Pic, vKey_RAlt w42 h34 xm+346 ym+186, key.jpg
Gui, Add, Pic, vKey_RWin w42 h34 xm+388 ym+186, key.jpg
Gui, Add, Pic, vKey_WTF w42 h34 xm+430 ym+186, key.jpg
Gui, Add, Pic, vKey_RCtrl w43 h34 xm+472 ym+186, key.jpg
Gui, Add, Pic, vKey_LeftArrow w34 h34 xm+532 ym+186, key.jpg
Gui, Add, Pic, vKey_DownArrow w34 h34 xm+566 ym+186, key.jpg
Gui, Add, Pic, vKey_RightArrow w34 h34 xm+600 ym+186, key.jpg

Gui, Show, h238 w653
Return

GuiClose:
ExitApp

AHK - Sender() and Reciever()

These two functions can be used to send short messages between AHK scripts without the use of temporary files. Here are the two functions:
Sender(Message) {
DetectHiddenWindows, On
WinGet, List, List, ahk_class AutoHotkey
Message := Message
Loop, %List%
SendMessage, % 1+4096,,,, % "ahk_id " List%A_Index%
Loop, Parse, Message
Loop, %List%
SendMessage, % asc(A_LoopField)+4099,,,, % "ahk_id " List%A_Index%
Loop, %List%
SendMessage, % 2+4096,,,, % "ahk_id " List%A_Index%
}


Loop, 258
OnMessage(A_Index+4096,"Reciever")
Return

Reciever(wParam, lParam, msg, hwnd)
{
Global Message
If (msg = 4097)
Message=
Else If (msg = 4098)
SetTimer, Handler, -1
Else
Message .= chr(msg-4099)
}

Handler:
MsgBox % Message
Return

And here is an example script. Run Recv.ahk before BCast.ahk.
; BCast.ahk
SetBatchLines, -1
Sender("Hello World!")
Sender(Message) {
DetectHiddenWindows, On
WinGet, List, List, ahk_class AutoHotkey
Message := Message
Loop, %List%
SendMessage, % 1+4096,,,, % "ahk_id " List%A_Index%
Loop, Parse, Message
Loop, %List%
SendMessage, % asc(A_LoopField)+4099,,,, % "ahk_id " List%A_Index%
Loop, %List%
SendMessage, % 2+4096,,,, % "ahk_id " List%A_Index%
}


; Recv.ahk
#Persistent
SetBatchLines, -1
Loop, 258
OnMessage(A_Index+4096,"Reciever")
Return

Reciever(wParam, lParam, msg, hwnd)
{
Global Message
If (msg = 4097)
Message=
Else If (msg = 4098)
SetTimer, Handler, -1
Else
Message .= chr(msg-4099)
}

Handler:
MsgBox % Message
Return

AHK - Tray Recycler

This is a script that creates a recycle bin on your tray. It is a good example of how to monitor and manipulate the recycle bin on your computer, and contains some functions that you can use. Currently the only thing that doesn't work is the "Create Shortcut" option.
; Flags for RecyleEmpty()
SHERB_NOCONFIRMATION := 1
SHERB_NOPROGRESSUI := 2
SHERB_NOSOUND := 4

#Persistent
CoordMode, Mouse, Screen
CoordMode, Pixel, Screen
WinGetPos, trayX, trayY, trayWidth, trayHeight, ahk_class Shell_TrayWnd
sysget, IconX, 49
sysget, IconY, 50
Gui, +ToolWindow -Caption +AlwaysOnTop
Gui, Margin, 0, 0
Gui, Add, Pic, Icon32 x0 y0 vRBPic h25 w-1, Shell32.dll
Gui, Show, Hide
LastRBPic := 0

Menu, Tray, NoStandard
Menu, Tray, Add, Open, RunRB
Menu, Tray, Add, Explore, ExpRB
Menu, Tray, Add, Empty Recycle Bin, EmptyRB
Menu, Tray, Add
Menu, Tray, Add, Create Shortcut, ShctRB
Menu, Tray, Add
Menu, Tray, Add, Properties, PropRB
Menu, Tray, Add, Exit, Exit
Menu, Tray, Default, Open
SetTimer, UpdateIcon, 100

UpdateIcon:
RecycleQueryAll(Size, NumItems)
T := NumItems ? 1 : 0
If (T <> PrevItems) {
Menu, Tray, Icon, Shell32.dll, % NumItems ? 33 : 32
If NumItems
Menu, Tray, Enable, Empty Recycle Bin
Else
Menu, Tray, Disable, Empty Recycle Bin
PrevItems := NumItems ? 1 : 0
}
Menu, Tray, Tip, Files: %NumItems%`nSize: %Size% Bytes

; Set GUI Window Position
ImageSearch, imageX, imageY, trayX, trayY, trayX+trayWidth, trayY+trayHeight, % "*120 *Icon" . (NumItems ? 33 : 32) . " Shell32.dll"
If (!ErrorLevel) {
MouseGetPos, MouseX, MouseY
If (mouseX >= imageX && mouseX <= imageX+IconX
&& mouseY >= imageY-26 && mouseY <= imageY+IconY-26
&& GetKeyState("LButton","P")) {
If (LastRBPic <> T)
GuiControl,, ShellIcon, % "*icon" . (NumItems ? 33 : 32) . " *w0 *h0 Shell32.dll"
Gui, Show, % "NA X" imageX " Y" imageY-26
}
Else
Gui, Hide
}
Return

GuiDropFiles:
Loop, Parse, A_GuiEvent, `n
FileRecycle, %A_LoopField%
Gui, Hide
Return

EmptyRB:
RecycleEmpty()
Return

ExpRB:
PropRB:
RunRB:
Run % (A_ThisLabel = "PropRB" ? "Properties "
: A_ThisLabel = "ExpRB" ? "Explore "
: "") . "::{645ff040-5081-101b-9f08-00aa002f954e}"
Return

ShctRB:
Return

Exit:
ExitApp

RecycleEmpty(Flag=0) {
DllCall( "Shell32\SHEmptyRecycleBinA", UInt,0, UInt,0, UInt,Flag )
}
RecycleQuery(Drive, ByRef i64Size, ByRef i64NumItems) {
pszRootPath := Drive . (StrLen(Drive) = 1 ? ":\" : "") . "..."
VarSetCapacity(pSHQueryRBInfo, 20, 0)
NumPut(20, pSHQueryRBInfo, 0, "UInt")

Result := DllCall( "Shell32\SHQueryRecycleBinA", Str, pszRootPath, UInt, &pSHQueryRBInfo )
/*
If (ErrorLevel || (A_LastError <> 0 && A_LastError <> 18)) {
MsgBox ErrLvl: %ErrorLevel%`nLstErr: %A_LastError%`nResult: %Result%
Return
}
*/
; typedef struct _SHQUERYRBINFO{
cbSize := NumGet(pSHQueryRBInfo, 0, "UInt")
i64Size := NumGet(pSHQueryRBInfo, 4, "UInt64")
i64NumItems := NumGet(pSHQueryRBInfo, 12, "UInt64")
; }
Return Result
}
RecycleQueryAll(ByRef Size, ByRef NumItems) {
Size := (NumItems := 0)
DriveGet, Drives, List, Fixed
Loop, Parse, Drives
{
RecycleQuery(A_LoopField, TSize, TNumItems)
Size += TSize
NumItems += TNumItems
}
}