상세 컨텐츠

본문 제목

[AHK] 사용 방법과 문법 - 3. Scripting Language

IT이야기/AutoHotkey

by Rahs 2019. 8. 19. 06:00

본문

주의

본 문서는 AutoHotkey 1.1 버전을 대상으로 작성되었습니다.

Usage and Syntax

Scripting Language

AHK 스크립트란 결국 프로그램이 따라야 할 일종의 지침을 AHK 언어로 기록해놓은 것이라고 할 수

있습니다. 이 AHK언어는 다른 프로그래밍 언어들과 유사한 부분도 있지만 AHK만의 장점과 단점을

가지며 본 문서에서는 AHK 언어에 대해 설명하고 사용 시 유의해야할 부분 등을 서술합니다.

이제야 기본적인 '스크립팅'에 대한 내용이 나오기 시작하는군요!

Table of Contents

  • General Conventions

  • Comments

  • Expressions

    • Strings / Text

    • Variables

    • Operators

    • Function Calls

    • Operators for Objects

    • Expression Statements

  • Legacy Syntax

  • Commands

    • OutputVar and InputVar Parameters

    • Text Parameters

    • Numeric Parameters

    • % Expression

    • Documentation Conventions

    • Optional Parameters

  • Expressions vs Legacy Syntax

    • Different Equals

    • Commands vs Functions

  • Control Flow Statements

    • Control Flow vs Commands

    • If Statement

    • Loop Statement

    • Not Control Flow

  • Structure of a Script

    • Auto-execute Section

    • Subroutines

    • User-Defined Functions

    • #include

  • Miscellaneous

    • Dynamic Variables

      • Pseudo-arrays

      • Associative pseudo-arrays

      • Commands which create pseudo-arrays

    • Labels

General Coventions

Names

  • 변수와 함수의 이름은 대소문자를 구분하지 않습니다.

  • 최대 길이 253자

  • _ # @ $와 숫자, non-ASCII 문자와 ASCII 문자 모두 사용 가능합니다.

No typed variables

변수의 형(type)을 명시적으로 지정하지 않습니다. 내장 변수(built-in variables)를 제외한 모든 변수에는

모든 타입의 값 1가지씩을 저장할 수 있습니다. 문맥에 따라 숫자는 문자열로 자동 변환되어

저장되거나, 그 반대로 문자열이 자동으로 숫자로 변환되어 저장될 수 있습니다.

Declarations are optional

functions 부분에서 명시된 일부 경우를 제외하고 변수는 사용 이전에 선언하지 않아도 사용이

가능합니다.

초기화가 컴파일 시 요구되지 않으며 모든 변수는 초기값으로 빈 공백 문자열 값을 가집니다.

Spaces are mostly ignored

코딩 시 가독성을 위해 들여쓰기가 필요한데 AHK는 이를 적극적으로 지원합니다.

해당 라인에서 문자가 시작되기 전의 모든 탭과 공백, 마지막 문자 이후의 모든 탭과 공백은 대부분의

경우 무시됩니다.

공백이 의미를 가지는 경우도 있는데 아래와 같은 경우가 이에 해당합니다.

  • 함수 또는 메서드(method: object 내에서 자체적으로 구현되어 있는 함수)를 호출 시 함수 또는

    메서드 이름과 ( 사이에 공백이 있어서는 안 됩니다. (e.g. execute() => o, execute () => x)

  • 변수명을 이용한 문자열 집합 연산 시 공백이 있어야 합니다.

    string1 = good
    string2 := " idea"
    string3 := string1 string2
    msgbox % string3
  • 표현의 모호성(ambiguity)을 없애기 위해 두 연산자 사이에 필요할 수 있습니다.

    Spaces may be required between two operators, to remove ambiguity.

    제가 이해를 못 했습니다. 아시는 분은 알려주세요.

  • 1줄짜리 주석은 해당 라인에 그 주석만 있는게 아니라면 공백 1칸을 띄고 기입해야 합니다.

    ;이건 괜찮습니다.
    msgbox message ;이건 앞에 한 칸 띄우고 사용해야 한다는 뜻입니다.

Line breaks are meaningful

줄바꿈(개행)은 지시문(statement)을 분리하는 용도로 사용됩니다.

여기서 지시문(statement)란 수행되어야 할 어떤 동작에 대한 가장 작은 명령문을 말합니다.

이전에 사용된 명령어나 표현식을 종료하는 의미로 사용됩니다.

유일한 예외가 바로 아래의 줄 연속사용(Line Continuation)입니다.

Line continuation

매우 긴 라인은 가독성과 유지보수성을 위해 짧은 라인으로 나눠쓸 수 있습니다. 이는 AHK에서

제공되는 기능이라기보다는 선처리를 통해 AHK가 여러 줄의 짧은 라인을 하나의 긴 라인으로

인식하도록 하는 것인데, 아래와 같은 2가지 방법이 있습니다.

  • Line continuation

    증감자(++, --) 연산자를 제외한, 다른 표현식 연산자로 시작하는 라인은 이전 라인과 함께 처리됩니다.

    msgbox good
    + idea ; 출력 시 good + idea가 표시됩니다.
    msgbox 1
    +2 ; 1+2 출력
    msgbox % 1
    +2 ; 3 출력
  • Continuation sections

    괄호()로 둘러싸인 한 section은 여러 라인으로 나뉘어있어도 한 라인으로 처리됩니다.

    단, 괄호는 각 라인에서 공백, 탭 등을 제외한 처음에 위치해야 합니다.

    string1 = 
    (
    good
    idea
      )
    msgbox % string1

Comments

주석은 프로그램이 무시하기로 약속되어 있는 텍스트라 할 수 있습니다. 보통 코드에 설명을

덧붙이거나 특정 부분의 코드를 잠시 사용하지 않을 때 많이 사용합니다.

기본적으로는 세미콜론(;)을 주석 flag로 사용합니다.

; 이 라인 전체가 주석으로 처리됩니다.

주석은 라인의 끝 부분에 추가할 수도 있습니다. 이 경우, 앞서 설명했듯이 세미콜론 앞에

최소 1개 이상의 공백 또는 탭이 필요합니다.

Run Notepad ; 이 주석은 명령문과 동일한 라인에 쓰여졌죠.

추가적으로 /*와 */를 이용해서 해당 영역 전체를 주석으로 처리할 수도 있습니다.

다만, 이 경우 각 기호들이 각 라인의 처음에 위치해야 한다는 점 유념하시기 바랍니다.

/*
MsgBox, 주석 처리되어서 실행되지 않고 오류도 나지 않습니다.
MsgBox, Common mistake: */ 라인의 처음이 아니기 때문에 주석은 여기서 끝나지 않습니다.
MsgBox, This line is commented out. 이게 주석의 마지막 줄입니다.
*/

주석은 실행 시 아예 무시되기 때문에 프로그램의 성능이나 메모리 점유에 아무런 영향을 미치지

않습니다.

기본 주석 문자는 세미콜론이지만 다른 문자 혹은 문자열로 변경할 수도 있습니다.

#CommentFlag 지시자를 통해 변경할 수 있지만 아래 2가지 이유로 사용이 권장되지는 않습니다.

  1. 대다수의 경우 사용 시의 이점보다 단점이 더 많습니다. (유지보수 시의 혼동 등)

  2. AutoHotkey v2부터는 더 이상 지원하지 않는 지시자입니다.

따라서 그냥 없다!고 생각하시고 세미콜론만 사용하는 걸로.. 저도 처음 알았습니다.

Expressions

''표현식''이란 하나 이상의 값, 변수, 연산자, 함수 호출의 조합을 의미합니다.

10, 1+1 혹은 MyVar 같은 표현식들은 모두 유효한 표현이라 할 수 있는 것입니다. 일반적으로 하나의

표현식은 1개 이상의 입력을 받으며 1개 이상의 연산을 수행하고, 하나의 결과 값을 표현하게 됩니다.

표현식의 값을 찾는 행위를 '평가'(evaluation)라 합니다.

1 + 1이라는 표현을 평가하면 숫자 2가 되는 원리입니다!

명령어(Commands)는 여러 개의 매개변수를 입력으로 받아서 한 가지 동작을 한 라인에서 실행합니다.

이 매개변수들이 다 표현식으로 구성된다고 볼 수 있는데, 표현식이 모여서 보다 복잡한 표현식을

구성하기도 합니다.

예를 들어, 할인율이 30이고 Discount라는 변수에 저장되어 있다고.. 아닙니다. 코드로 보시죠.

price := 50000
discount := 30
msgbox % discount/100 ; 할인율을 소수로 나타낸 표현입니다. 평가값을 대화상자로 출력합니다.
msgbox % 1 - discount/100 ; 잔액 비율을 나타내는 표현이 되겠죠.
msgbox % price * (1 - discount/100) ; 물건 구매가를 나타내는 표현입니다.

Strings / Text

문자열입니다. 텍스트죠. 보통 쌍따옴표로 묶어서 표현됩니다.

string1 = 이건 묶이지 않았지만 등호로 표현되어서 문자열로 인식됩니다.
string2 := "이건 := 기호를 사용했기 때문에 쌍따옴표로 묶어주면 문자열로 인식됩니다"
string3 := "쌍따옴표를 문자열 안에서 표현하고 싶을 때는 두번 연달아 써줍니다. ""이렇게""요."
msgbox % string1
msgbox % string2
msgbox % string3

쌍따옴표로 표현된 문자열 안에서는 탭, 개행, CR 표현도 escaping 문자(`)를 이용해 할 수 있습니다.

string1 := "여기서 ""줄""을 바꾸고`n여기서는 탭`t탭탭`t`t그리고 캐리지 리턴`r!!"
msgbox % string1

Variables

변수는 이름을 표현식에 그대로 담으면 사용되지만 쌍따옴표 안에서는 사용할 수 없습니다.

문자열과 같이 사용할 때는 아래와 같은 2가지 방법 중 하나를 사용합니다.

MyVar := "concatenated."
string1 := "The values are " MyVar   ; 묵시적 문자열 합연산
string2 := "The values are " . MyVar ; 명시적 문자열 합연산

묵시적인 경우에는 공백이, 명시적인 경우에는 점(.)과 앞뒤 공백이 필수적이라는 점만 기억하고

편한대로 사용하면 되겠습니다.

또는 Format 함수를 사용할 수도 있습니다.

msgbox % Format("this is {1} I can show {2}", "what", "you")

아까부터 % 기호가 계속 나오고 있는데, 이건 본 문서 하단에 상세한 설명이 나옵니다 :)

Operators

연산자로는 +나 :=와 같은 기호가 사용되고, and, or, not, new의 단어가 사용되는 경우도 있습니다.

1개 이상의 입력을 받아서 정의된 연산을 수행하고 결과를 반환해주는 역할을 하는데, 이 때 입력으로

사용되는 값들을 피연산자(operand)라고 부릅니다.

  • 단항(unary) 연산자는 연산자의 종류에 따라 연산자의 앞 또는 뒤에 사용됩니다.

e.g.) -x , not keyIsDown

  • 이항(binary) 연산자는 두 피연산자 사이에 사용됩니다.

e.g.) 1+1, 2*5

  • AHK는 단 하나의 삼항(trinary) 연산자를 제공합니다.

e.g.) condition ? valueIfTrue : valueIfFalse

그 외 연산자의 성질(연산 순서 등)은 대부분 사칙연산의 그것을 따릅니다.

Function calls

함수는 정해진 동작을 수행해서 결과 값을 반환해줍니다. 함수의 입력으로 주어지는 표현식을

'매개변수'라고 부르며, 함수 이름 뒤에 공백없이 괄호를 붙여 함수를 호출할 수 있습니다.

예로써 GetKeyState("Shift") 를 살펴보면 GetKeyState 함수를 괄호를 이용해 호출하고 있으며

매개변수로 "Shift"라는 문자열을 전달하고 있습니다.

AHK에서 제공되는 함수로, 모든 스코프에서 사용이 가능하며 저 함수의 경우에는;

Shift 키가 눌려있다면 1을,

그렇지 않다면 0을

반환해줍니다.

Operators for Objects

객체와 함께 사용되는 연산자들은 지금까지 설명된 내용들과 궤를 조금 달리합니다. 낯설어 보일 수도

있고, 이제야 좀 언어 같네!라고 하실 분들도 많으실 것이라 생각합니다.


Alpha.Beta 멤버 접근입니다. Alpha라는 객체가 가지는 멤버 중 Beta에 대해 접근하는 연산자입니다.

Alpha 객체에게 '네가 가지고 있는 속성 중 Beta라는 애 좀 넘겨줘'로 이해하시면 되겠습니다.

Alpha.Beta() 메서드 호출입니다.

Alpha.Beta[Param] Beta라는 멤버에 추가적인 매개변수를 전달할 때 사용합니다.

Beta는 단순히 '이름'일 뿐이지만 매개변수는 값이나 표현식, 또는 쉼표(,)로 분리된 표현식 리스트일

수 있습니다.

Alpha[Index] Alpha.Beta와 굉장히 비슷합니다. 다만 전자와는 달리 Alpha와 Index 둘 모두

표현식으로의 대체가 가능합니다. 이 형식의 문법은 보통 배열이나 복합 배열(associative array)에서

값을 추출할 때 사용됩니다.

new ClassName() 클래스를 생성하는데 사용됩니다. 함수 호출처럼 보이지만 함수는 아니고 여기서의

ClassName은 생성될 클래스의 이름 값일 뿐입니다. new Alpha.Beta()와 같이 사용하면

Alpha.Beta로 접근이 가능한 객체를 생성해서 돌려주게 됩니다.

[A, B, C] 초기값 A, B, C를 가지는 배열을 생성합니다.

여타 언어들과 다르게 AHK에서 모든 index는 1부터 시작한다는 점을 기억해두면 편리합니다.

{Key1: Value1, Key2: Value2} 복합 배열을 생성합니다. 키와 값의 짝으로 이루어진 배열로 이해하면

되며, 각 값은 그에 상응하는 키를 통해 객체로부터 얻어질 수 있습니다. 복합 배열 안에는 값 또는

특정 값을 가지는 변수의 형태 그대로도 저장이 가능합니다.

예로써 {A: B}는 {"A": B}와 동일합니다만, {(A): B}는 A라는 변수에 저장된 값이 실질적인 키가 됩니다.

MyFunc(Params*) 임의 개수의 매개변수를 전달받을 수 있는 함수를 호출하는 방법입니다.

별표(*)는 반드시 닫는 괄호 직전에 위치할 수 있고, 함수가 2개 이상의 매개변수를 전달받는 경우,

언제나 마지막 매개변수로만이용될 수 있습니다.

Params는 배열 객체의 이름이거나, 배열 객체를 반환하는 표현식이어야 합니다.

별표를 아무데서나 사용할 수 있는 것은 아니지만 예외적으로 위의 경우와 아래와 같은 경우에

사용 가능합니다.

  • 배열 정의 시 다른 배열을 덧붙일 경우 [A, B, C, ArrayToAppend*]

  • 배열 자체를 인덱스로 사용하는 경우 Alpha[Params*]

Expression Statement

표현식은 그 자체만으로는 별다른 쓸모가 없습니다. 예제로 보겠습니다.

; 1 + 2 ; 그냥 표현식으로 컴파일도 되지 않습니다. 이건 expression statement라고 하지 않죠.
a := 1 + 2 ; 이건 expression statement입니다. 두 값을 더해 변수 a에 값을 저장하고 있죠.
msgbox % a ; 그리고 우리 눈에 보이게 대화상자로 표시해줍니다.

Legacy Syntax

코딩을 하다 보면 legacy라는 단어를 많이 접하게 됩니다. 우리 말로는 적절하게 옮기기가 쉽지

않은데, 본 블로그 및 본문에서는 '기존 방식'이라는 표현으로 대체합니다.

기존 방식의 문법(명령어 문법)은 라인당 한 가지 동작 수행을 기본 전제로 하고 있었습니다.

특정 프로그램을 수행하거나 키 입력을 보내는 등 어느 정도 정형화된 작업을 수행하기 위한

스크립트를 아래의 구성 요소들만으로 만들 수 있죠.

  • 명령어

  • 변수명

  • 따옴표로 묶이지 않은 텍스트

  • 콤마(,)

  • 등호(=)

  • 퍼센트 기호(%)

따옴표로 묶이지 않은 텍스트(unquoted text)라는 말은 정말 말 그대로 그냥 텍스트를 말합니다.

텍스트라는 것을 알려줄 시작 구분자나 끝 구분자가 없기 때문에 줄의 마지막에 위치하거나

마지막 매개변수로 사용되며, 전후의 공백이나 탭 문자는 무시됩니다.

다음 문자들은 이 '따옴표로 묶이지 않은 텍스트' 내에서 부가적인 의미를 가집니다.

  • % 이 퍼센트 기호로 변수명을 둘러싸면 해당 부분 전체가 변수의 값으로 대체됩니다.

    msgbox % The year is %A_Year% ; A_Year은 내장변수로 현재 날짜의 연도를 말합니다.

    단순 변수만 이런 식으로 포함해서 사용이 가능하며 배열 요소나 속성, 기타 표현식은

    이런 식으로 단순 텍스트 내에서의 대체 사용이 지원되지 않습니다.

  • , 쉼표는 대개 명령어의 매개변수 구분자로 사용됩니다.

  • ` escape character로 해당 문자 바로 다음에 따라오는 문자에 따라 다른 의미를 가지게 됩니다.

    `%는 위에서 설명된 변수 대체용이 아닌 그냥 있는 그대로의(literal) 퍼센트 기호를 의미하게 되고,

    `, 역시 마찬가지로 구분자로서의 쉼표가 아니라 그냥 쉼표를 표시하게 됩니다.

    탭(t)과 개행(n), 캐리지 리턴(r) 모두 마찬가지 방식으로 사용됩니다.

명령어에는 이 '텍스트'와 변수명, 숫자 표현식 등을 모두 사용할 수 있습니다.

msgbox,,,The time is %A_Hour% o'clock.

기존 방식으로 '텍스트'를 변수 값으로 할당할 수도 있습니다.

Clipboard = This text is copied to the clipboard.

If문을 사용하면 특정 조건이 만족되었을 때만 동작이 수행되도록 할 수 있습니다. 이 외에도 loop 등의

여러 제어문에서 명령어와 유사하게 기존 방식의 문법이 사용되고 있으니 눈에만 익혀놓도록 합니다.

Commands

명령어를 이용하면 사전에 정의된 특정한 동작을 간편하게 수행할 수 있습니다. 명령어는 정의되어

있는 것만 사용할 수 있으며, 변경하거나 제거할 수는 없습니다.

명령어는 간단하게 스크립트 라인 가장 처음에 해당 명령어의 이름과 필요한 매개변수를 나열해서

사용할 수 있는데 사용 방법은 아래와 같습니다.

msgbox, The time is %A_Hour% o'clock

쉼표(,)가 명령어 이름과 매개변수를 분리해주고 있음을 볼 수 있습니다.

생략이 가능한 경우도 있지만 아래 2가지 경우에는 생략되어서는 안 됩니다.

  • 생략되었을 때 기존 방식 문법과 혼동을 일으킬 수 있는 경우

    msgbox, := 이건 쉼표가 없으면 변수 할당하는 것처럼 보이겠지요.
  • 첫번째 매개변수가 생략되었을 때

    msgbox,, second, third
    ; msgbox는 첫번째 매개변수로 대화상자의 타입, 두번째 매개변수로 대화상자의 제목, 세번째 매개변수로
    ; 대화상자의 내용을 받습니다. 쉼표가 없다면 두번째 매개변수가 첫번째 매개변수로 오인되겠죠?

명령어에 따라 필요로 하는 매개변수는 다 다르지만 대체적으로 아래 4가지의 타입으로 분류됩니다.

  • 출력값

  • 입력값

  • 문자열

  • 숫자

그리고 대부분의 경우 퍼센트 기호를 이용해서 표현식을 매개변수로 전달해줄 수 있습니다.

OutputVar and InputVar Parameters

출력변수와 입력변수로는 변수명 또는 동적 변수 참조를 사용할 수 있습니다.

동적 변수 참조란 퍼센트 기호(%)로 변수명을 감싸서 변수 값을 표현한 표현식을 말합니다.

StringReplace, NewStr, OldStr, %A_Space%, +, All

내장 변수 A_Space는 공백 한칸(" ")을 가리킵니다.

명령어 StringReplace의 시그니쳐는 아래와 같은데 이는 Scite4Autohotkey에서 StringReplace를

입력한 뒤,쉼표(,)를 입력해보면 아래 툴팁으로 표시되니 참고하시면 좋겠습니다.

StringReplace, OutputVar, InputVar, SearchText [, ReplaceText, All]

시그니쳐와 코드를 비교해보면 OutputVar로 NewStr이, InputVar로 OldStr,

SearchText로 %A_Space%가, ReplaceText로 +, 마지막에 All 이라는 옵션이 사용되었다는 것을

알 수 있습니다.

OldStr = 띄워쓰기가 플러스로 모두 교체됩니다
StringReplace, NewStr, OldStr, %A_Space%, +, All
msgbox % NewStr ; 띄워쓰기가+플러스로+모두+교체됩니다

StringReplace, NewerStr, NewStr, +, %A_Tab%
msgbox % NewerStr ; All이 없으니 첫번째 +만 탭으로 교체합니다.

Text Parameters

따옴표로 감싸지 않아도 예제들처럼 텍스트 그대로 사용이 가능합니다.

다만 쉼표(,)와 퍼센트 기호(%)는 각각의 역할이 있는만큼, 해당 기호들을 텍스트 내에서 사용하기

위해서는 escaping character(`)를 꼭 사용해야 합니다. 간단히 예제로 보고 넘어가겠습니다.

msgbox 쉼표(`,)나 퍼센트 기호(`%)를 표시하려면 이스케이핑 문자(``)를 사용합니다.

Numeric Parameters

타 언어를 사용해보신 분들께는 조금 의아하면서도 흥미로울 수 있는 부분이겠네요.

숫자 표현 자체에는 별다른 특이사항이 없습니다만 아래와 같은 사용이 가능합니다.

fifty := 50
fiveHundred = %fifty%0
fiftyString = fifty
msgbox % fiveHundred + 100 ; 600
msgbox % fiftyString ; fifty
msgbox % %fiftyString% ; 50

% Expression

드디어 궁금해하시던 퍼센트 기호에 대한 내용이 나왔습니다.

MillisecondsToWait := 500
Sleep MillisecondsToWait
msgbox 0.5s elapsed
Sleep %MillisecondsToWait%
msgbox 0.5s elapsed
Sleep % MillisecondsToWait
msgbox 0.5s elapsed

제일 앞에 %와 공백(" ")을 붙여서 이후 퍼센트 기호를 생략하는 것을 percent-space prefix라 합니다.

대부분의 경우 유용하게 사용이 가능하지만 아래 경우들에서는 사용할 수 없습니다.

  • 기존 방식의 If 문법에서는 사용할 수 없습니다. 본 문서에서는 기존 방식의 If에 대해 다루지 않고,

    보다 개선된 방식의 If (expression)만 사용할 예정이기 때문에 무시하셔도 좋습니다.

  • OutputVar 매개변수에는 percent기호 자체를 사용할 수 없습니다.

Documentation Conventions

명령어 또는 함수의 시그니쳐에 대한 이해 부분입니다.

StringLower, OutputVar, InputVar [, T]

위와 같은 시그니쳐가 주어졌을 경우, 대괄호([])로 싸여있는 부분은 생략이 가능하고, 필요에 따라

사용할 수 있다는 의미입니다.

Optional Parameters

위 컨벤션에서 언급된 '생략 가능한' 부분은 쉼표를 포함해서 통으로 생략가능했지만,

이 세션에서 말하는 '선택 가능한 매개변수'는 '비워둘 수 있다'는 의미입니다.

Run, notepad.exe,, Min

Run 명령어의 두번째 매개변수는 workingDir입니다. 메모장 켜는데 workingDir을 지정할 필요는 없죠.

하지만 세번째 매개변수에 Min을 명시하기 위해 그냥 비워진 형태로 사용한 예가 되겠습니다.

실행해보시면 최소화된 상태로 메모장이 실행됩니다.

Expressions vs Legacy Syntax

대부분 명령어에서는 매개변수로 표현식을 있는 그대로는 사용할 없습니다. 퍼센트 기호로 감싸줘서

표현식의 평가값(evaluate)을 넘겨줘야 합니다. 굳이 구분하려고 하지 마시고, 사용 방식에 따라 결과가

어떻게 나오는지 감을 잡으시면 이 시점에서는 그걸로 충분하겠습니다.

MsgBox % 1+1  ; Shows "2"
MsgBox   1+1 ; Shows "1+1"
MsgBox % "This is text."
MsgBox   This is text.
MsgBox %  A_AhkVersion
MsgBox   %A_AhkVersion%
MsgBox % "Hello %A_UserName%."  ; Shows "%A_UserName%"
MsgBox   Hello %A_UserName%.   ; Shows your username.
MsgBox % "Hello " . A_UserName . "."  ; Shows your username.
MsgBox % Format("Hello {1}.", A_UserName)  ; {} also works in place of {1}.
MyVar := "This is text."
MyVar = This is text.
if (Var1 = Var2)
if Var1 = %Var2% ; 이 형태의 사용은 권장하지 않습니다.
if (Var1 >= Low and Var1 <= High)
if Var1 between %Low% and %High% ; 이 형태의 사용은 권장하지 않습니다.

Different Equals

AHK에서는 두 종류의 등호 기호가 사용됩니다. =:=가 그것인데요, 혼동하기가 쉬워서 초반에

애를 먹는 경우가 많습니다. 아래 예를 보실게요.

A = 50  ; A에 텍스트 50을 저장합니다.
B := 20 ; B에 숫자 20을 저장합니다.

Total1 = A + B ; 이 경우, 텍스트 A + B가 Total1 변수에 저장됩니다.
Total2 := A + B ; 이 경우, A는 산술 연산자 +때문에 숫자로 변환되어 70이 Total2 변수에 저장됩니다.
msgbox % Total1
msgbox % Total2

뭔가 '그대로' 저장하고 싶은 경우가 아니라면 :=를 사용하는 습관을 들이는 것을 추천드립니다.

Commands vs Functions

현재 버전에서는 경우에 따라 편한 방식으로 사용하면 됩니다.

명령어와 함수가 어느 정도 공존하고 있거든요.

단순히 값을 추출해서 다음번에 해당 값을 사용하는 목적이라면 명령어도 나쁘지 않습니다.

하지만 다른 표현 내에서 해당 값이 바로 필요한 경우라면 별도로 값을 할당할 필요 없이 함수로

대체하는 것이 좋은 것처럼요..?

CommandReplacement
FileAppendFileOpen and File.Write
FileGetAttribFileExist
FileReadFileOpen and File.Read
GetKeyStateGetKeyState (the function returns 0 or 1, not "U" or "D")
IfExistFileExist
IfInStringInStr
IfWinActiveWinActive
IfWinExistWinExist
StringGetPosInStr
StringLenStrLen
StringReplaceStrReplace
StringSplitStrSplit
StringLower StringUpperFormat("{:L}", input), Format("{:U}", input) or Format("{:T}", input)
StringLeft StringMid StringRight StringTrimLeft StringTrimRightSubStr

Control Flow Statements

말은 길고 복잡하지만 우리말로 줄이면 '제어문'입니다. 간략하게 설명 옮기겠습니다.

  • block(이하 블락)은 한 짝의 중괄호({})로 표현됩니다. 명령문의 단위를 결정짓는 역할을 합니다.

    if, else와 함께 많이 사용될 때의 그 역할 그대로를 생각하시면 되겠습니다.

    타 언어와 달리 스코프와는 연관이 없습니다.

  • Goto는 명시된 label로 건너뜁니다. label의 위치에 따라 되돌아가기도 하구요.

  • GoSub은 명시된 label로 갔다가 return문을 만나면 다시 돌아와요.

    msgbox 1
    start:
    goto, end

    msgbox never
    middle:
    msgbox 3
    return

    end:
    msgbox 2
    gosub, middle
    msgbox 4
  • Loop는 반복을 위한 키워드입니다. Loop, While, For의 3가지 종류가 있습니다.

    • break는 해당 반복 구간에서 바로 빠져나갑니다.

    • continue는 해당 반복 구간의 남은 부분을 무시하고 계속 반복을 진행합니다.

    • until은 해당 조건이 만족될때까지 loop문을 실행시킵니다.

      count := 0 ; 초기화를 하지 않으면 공백(' ')이 되고, 공백에는 증감연산이 적용되지 않아서
      Loop       ; 무한루프를 돌게 됩니다.
      {
      msgbox % ++count
      } Until (count = 2)
  • 예외 처리

    정말 '예상 외의' 어떤 오류가 생겼을 때, 해당 오류를 처리하거나, 개발자가 의도하지 않은 상황이

    발생했을 때 해당 상황에 대한 대응을 미리 코드에 담아놓는 것을 말합니다.

    try  ; Attempts to execute code.
    {
      HelloWorld()
      MakeToast()
      Msgbox, This message never shows up!
    }
    catch e ; Handles the first error/exception raised by the block above.
    {
      MsgBox, An exception was thrown!`nSpecifically: %e%
      Exit
    }

    HelloWorld() ; Always succeeds.
    {
      MsgBox, Hello, world!
    }

    MakeToast() ; Always fails.
    {
      ; Jump immediately to the try block's error handler:
      throw A_ThisFunc " is not implemented, sorry"
    }

Control Flow vs Commands

If Statement

Loop Statement

AHK에서 제공하는 몇 가지 유용한 종류의 loop들이 있습니다. 꼭 기억해두고 찾아쓸 수 있어야 합니다.

  • Loop count

  • Loop Reg

  • Loop Files

  • Loop Parse

  • Loop Read

t := "column 1`tcolumn 2`nvalue 1`tvalue 2"
Loop Parse, t, `n
{
  rowtext := A_LoopField
  rownum := A_Index ; Save this for use in the second loop, below.
  Loop Parse, rowtext, `t
  {
      MsgBox %rownum%:%A_Index% = %A_LoopField%
  }
}

Not Control Flow

Structure of a Script

Auto-execute Section

스크립트가 로드되면 스크립트상의 첫 label, return, Exit 또는 ExitApp을 만나기 전까지 스크립트대로

프로그램이 수행됩니다. 스크립트의 가장 첫번째 label은 이 맥락에서는 return과 동일하게 취급된다는

것을 기억해두도록 합니다.

다시 말해서 스크립트의 가장 처음 부분은 무조건 실행된다는 거죠.

msgbox 스크립트가 실행되었습니다
; << 여기에 return이 있거나 말거나 동일하게 동작합니다.
!1::
msgbox Alt+1 키가 눌렸습니다
return

!2::
msgbox Alt+2 키가 눌렸습니다
return

Subroutines

User-Defined Functions

#include

특정 파일의 내용을 정확히 이 이 지시자가 있는 자리에 포함시키고 싶을 때 사용하는 지시자입니다.

보통 스크립트의 첫 부분이 명시적으로 사용되고 중간 부분에 사용한다거나 하지는 않습니다.

value.ahk

value := 10

check.ahk

#include value.ahk
msgbox % value ; 10

C/C++과 달리 한번 include된 파일을 다시 include하면 두번째 include는 깔끔하게 무시해줍니다.

의도적으로 여러 번 include가 필요한 경우에는 #includeAgain을 사용하면 됩니다.

함수 등이 선언된 파일의 경우 명시적으로 #include 지시자를 사용하지 않아도 파일이름만 적절하게

정의되어 있으면 AHK가 알아서 파일 내용을 끌어쓰게 되는데 이 부분은 Library of Functions에서

다시 다루겠습니다.

Miscellaneous

Dynamic Variables

target := 42
second := "target"
MsgBox   %second% ; Normal (single) variable reference in text => target
MsgBox % second   ; Normal (single) variable reference in an expression => target
MsgBox % %second% ; Double-deref in an expression => 42

동적 변수라고 이름이 거창하지만 결국 앞서 설명했던 바로 그 내용입니다 :)

Psedo-arrays

실제로는 단순히 변수에 저장된 값들이지만 마치 배열인 것처럼 사용하는, 유사 배열을 말합니다.

예제로 보는게 편하죠.

MyArray1 = A
MyArray2 = B
MyArray3 = C
Loop 3
  MsgBox % MyArray%A_Index% ; Shows A, then B, then C.

Associative pseudo-arrays

자료구조 중에 Map과 비슷한 사용 방법을 가집니다. 복합유사배열이라고 할까요?

SysGet, WA, MonitorWorkArea
MsgBox, Left: %WALeft% -- Top: %WATop% -- Right: %WARight% -- Bottom: %WABottom%.

Commands which create pseudo-arrays

위의 복합유사배열이 적극적으로 활용되는 명령어들이 몇 가지 있습니다.

공교롭게도 유용한 명령어들이 많기 때문에 짚어보고 넘어갈 필요가 있습니다.

사용이 필요한 시점에 예제를 함께 작성해놓겠습니다.

  • GuiControlGet Pos 윈도우 컨트롤의 좌표 정보를 해당 형태로 돌려줍니다.

  • RegExMatch

  • SysGet의 Monitor/MonitorWorkArea (위 예제에 나온 명령어입니다)

  • WinGet List

Labels

레이블에는 3가지 종류가 있습니다.

  • 일반 레이블

    msgbox 1
    gosub, normalLabel
    return
    normalLabel:
    msgbox 2
    return
  • hotkey 레이블

    !1::
    msgbox Alt+1 키가 눌렸습니다.
    return
  • hotstring 레이블

    실행시켜놓고 메모장 등에서 btw라고 입력하고 띄워쓰기를 하면 by the way로 글자가 변경됩니다.

    ::btw::by the way

이제 상세한 내용들이 슬슬 나오기 시작합니다.

어설프게 예제위주로만 따라 만들다가 메뉴얼 제대로 천천히 읽어보니 그동안 몰랐던 부분들이

생각만큼 많네요(...) 역시 블로그는 자기계발이 제맛이죠, 암요 :)

End of Document


관련글 더보기

댓글 영역