키 입력 보내는 방법
키 입력 보내는 방법 (How to Send Keystrokes)
AutoHotkey로 키 입력(key)을 보내는 코드를 작성하는 방법과, 그 키 입력을 보내는 다양한 모드·옵션을 설명하는 문서예요.
출처: 문서
본문
Send "Hello, world{!}{Left}^+{Left}"
키 입력(줄여서 키)을 보내는 것은 프로그램을 자동화하는 가장 일반적인 방법이에요. 가장 일반적으로 동작하기 때문이에요. 더 직접적인 방법들은 특정 유형의 응용 프로그램에서만 동작하는 경향이 있어요.
키 보내는 법을 배우는 데는 대체로 두 부분이 있어요:
- 프로그램이 어떤 키를 보내길 원하는지 알 수 있도록 코드를 작성하는 방법.
- 올바른 최종 결과를 얻기 위해 사용 가능한 모드와 옵션을 사용하는 방법.
키를 보내는 것이 물리적으로 키를 누르는 행위를 완벽하게 재현하지는 않는다는 것을 이해하는 것이 중요해요. 심지어 인간 속도로 늦춰도 마찬가지예요. 하지만 그렇게 들어가기 전에 몇 가지 기본을 다룰게요.
예시 시험해 보기 (Trying the examples)
SendText "Hi!" 같은 예시를 실행하면 그 텍스트는 즉시 활성(포커스된) 창으로 보내져서, 예시를 어떻게 실행했느냐에 따라 별로 유용하지 않을 수 있어요. 보통은 핫키를 정의하고, 예시를 로드하기 위해 실행한 다음, 그 효과를 테스트하고 싶을 때 핫키를 누르는 것이 더 좋아요. 아래 예시 중 일부는 ^1:: 같은 번호가 매겨진 핫키를 사용할 거예요(Ctrl과 숫자라서 중복이 없으면 여러 예시를 한 번에 시도할 수 있어요). 하지만 그것을 자신에게 맞는 것으로 바꿀 수 있어요.
핫키를 사용자 지정하거나 직접 만드는 법을 배우려면 How to Write Hotkeys를 참조해요.
예시를 어떻게 시험할지 확실하지 않다면 How to Run Example Code를 참조해요.
코드 작성 방법 (How to write the code)
키를 보낼 때, 보통은 그 효과를 위해 키나 키 조합을 보내거나(Ctrl+C를 눌러 클립보드에 복사하는 것처럼), 어떤 텍스트를 입력하거나 해요. 텍스트를 입력하는 것은 더 단순하므로 거기부터 시작할게요. SendText 함수를 호출하고 보내려는 정확한 텍스트를 전달하면 돼요.
^1::SendText "To Whom It May Concern"
기술적으로 SendText는 실제로 키 입력이 아니라 유니코드 문자 패킷을 보내며, 그 덕분에 Shift+2나 AltGr+a처럼 키 조합으로 보통 입력되는 문자에 훨씬 더 안정적이에요.
인용 문자열의 규칙 (Rules of quoted strings)
SendText는 텍스트를 그대로 보내지만, 언어의 규칙을 명심하세요. 예를 들어, 리터럴 텍스트는 인용부호(이중 " 또는 단일 ')로 감싸야 하며, 인용부호 자체는 SendText 함수가 "보지" 못해요. 리터럴 인용부호를 보내려면 그것을 반대 종류의 인용부호로 감쌀 수 있어요. 예를 들어:
^2::SendText 'Quote marks are also known as "quotes".'
또는 이스케이프 시퀀스를 사용해요. 인용된 문자열 안에서 `"는 리터럴 "로 변환되고 `'는 리터럴 '로 변환돼요. 예를 들어:
^3::{
SendText "Double quote (`")"
SendText 'Single quote (`')'
}
인용부호를 교대로 사용할 수도 있어요:
^4::SendText 'Double (") and' . " single (') quote"
두 문자열은 SendText 함수에 전달되기 전에 서로 합쳐져요(연결, concatenated). 점(.)은 생략할 수 있지만, 생략하면 한 문자열이 끝나고 다른 것이 시작되는 곳을 보기 어려워져요.
위에서 보았듯이 이스케이프 문자 `(백쿼트, 백틱, 중음 부호 등으로 알려진)는 특별한 의미를 가지므로, 그 문자를 리터럴로 보내려면(또는 해당 키를 보내려면) Send "``"처럼 두 배로 해야 해요. 다른 일반적인 이스케이프 시퀀스로는 줄바꿈(Enter)용 `n과 탭용 `t가 있어요. 더 자세한 내용은 Escape Sequences를 참조해요.
키와 키 조합 보내기 (Sending keys and key combinations)
SendText는 텍스트를 그대로 보내는 데 가장 좋지만, Left나 Home처럼 텍스트를 만들지 않는 키는 보낼 수 없어요. Send, SendInput, SendPlay, SendEvent 및 ControlSend는 텍스트와 키 조합, 또는 텍스트를 만들지 않는 키를 모두 보낼 수 있어요. 이 모든 것을 하기 위해 그것들은 다음 기호에 특별한 의미를 부여해요: ^!+#{}
처음 네 기호는 표준 수식 키인 Ctrl(^), Alt(!), Shift(+) 및 Win(#)에 해당해요. 그것들은 조합으로 사용될 수 있지만, 그 외에는 다음 키에만 영향을 줘요.
키를 이름으로 보내거나 위 기호 중 하나를 리터럴로 보내려면 중괄호로 감싸요. 예를 들어:
^+{Left}는 Ctrl+Shift+Left를 만듦.^{+}{Left}는 Ctrl++ 다음 Left를 만듦.^+Left는 Ctrl+Shift+L 다음 리터럴 문자 eft를 만듦.
Ctrl+Shift+"를 누르면 다음 예시는 두 개의 인용부호를 보낸 다음 삽입점을 왼쪽으로 옮겨서 인용부호 안에 입력할 준비를 해요:
^+"::Send '""{Left}'
^!+#{}가 아닌 단일 문자는 Send가 해당 키 조합으로 변환하고 그 조합을 눌렀다 놓아요. 예를 들어, Send "aB"는 A를 눌렀다 놓고, 그다음 Shift+B를 눌렀다 놓아요. 마찬가지로, 중괄호로 감싼 어떤 키 이름이든 기본적으로 눌렀다 놓아요. 예를 들어, Send "{Ctrl}a"는 Ctrl을 눌렀다 놓은 다음 A를 눌렀다 놓을 거예요. 아마 여러분이 원하는 것이 아닐 거예요.
키를 눌러(누르고 있기)만 하거나 놓기만 하려면 키 이름을 중괄호로 감싼 다음 공백과 "down" 또는 "up"이라는 단어를 붙여요. 다음 예시는 Ctrl+CapsLock이 Shift의 토글 역할을 하게 해요:
*^CapsLock::{
if GetKeyState("Shift")
Send "{Shift up}"
else
Send "{Shift down}"
}
핫키 대 Send (Hotkeys vs. Send)
경고: 핫키와 Send에는 알아야 할 몇 가지 차이가 있어요.
핫키도 ^!+# 기호와 같은 키 이름을 사용하지만, 몇 가지 중요한 차이가 있어요:
- 다른 핫키 수식 기호는 Send가 지원하지 않아요. 예를 들어,
>^a::은 RCtrl+A에 해당하지만, 그 조합을 보내려면Send "{RCtrl down}a{RCtrl up}"처럼 키 이름을 온전히 적어야 해요. - 핫키에서는 키 이름이 절대 중괄호로 감싸지 않지만, Send에서는(한 문자보다 길다면) 항상 중괄호로 감싸야 해요.
- Send는 대소문자를 구분해요. 예를 들어,
Send "^A"는 Ctrl과 대문자 "a"의 조합을 보내므로 Ctrl+Shift+A가 돼요. 반대로^a::과^A::은 동일해요.
이것은 Send가 여러 목적을 제공하는 반면, 핫키는 키 조합에 최적화되어 있기 때문이에요.
관련해서, 핫스트링은 텍스트 입력 감지 전용이므로 ^!+#{} 기호는 핫스트링 트리거 텍스트 안에서 특별한 의미가 없어요. 하지만 핫스트링의 대체(replacement) 텍스트는(T 옵션을 사용할 때를 제외하면) Send와 같은 문법을 사용해요. 다음 핫스트링이 활성 상태일 때 "{"를 입력하면 "}"를 보낸 다음 삽입점을 중괄호 사이로 되돌리기 위해 Left를 보내요:
:*?B0:{::{}}{Left}
블라인드 모드 (Blind mode)
일반적으로 Send는 물리적으로 누르고 있는 수식 키가 보내라고 지시한 키와 결합되지 않아야 한다고 가정해요. 예를 들어, Ctrl을 누른 채 Send "Hi"를 호출하면 Send는 "Hi"를 보내기 전에 자동으로 Ctrl을 놓고, 그 후에 다시 눌러요.
때로는 원하는 것이 이전에 눌렸거나 보내진 다른 수식 키와 조합해서 일부 키를 보내는 것일 수 있어요. 이렇게 하려면 {Blind} 접두사를 사용할 수 있어요. 다음 예시를 실행하는 동안 비어 있지 않은 텍스트 편집기나 입력 필드에 포커스를 두고 Ctrl 또는 Ctrl+Shift를 누른 채 1이나 2를 눌러 보세요:
*^1::Send "{Blind}{Home}"
*^2::Send "{Blind}{End}"
{Blind}에 대한 자세한 내용은 Blind mode를 참조해요.
그 외 (Others)
Send는 다른 몇 가지 특수 구문을 지원해요. 예를 들어:
{U+00B5}는 서수 값(문자 코드)으로 유니코드 문자를 보내는 용도.{ASC 0181}는 Alt+Numpad 시퀀스를 보내는 용도.{Click Options}는 클릭하거나 마우스를 움직이는 용도.
전체 목록은 Key names을 참조해요.
모드와 옵션 (Modes and options)
키를 보내는 것은 물리적으로 키를 누르는 행위를 완벽하게 재현하지 않아요. 운영 체제는 키를 보내는 여러 가지 다른 방법을 제공하며, 각각 다른 주의 사항이 있어요. 때로는 원하는 결과를 얻으려면 다른 방법을 시도할 뿐 아니라 타이밍도 조정해야 해요.
주요 방법은 SendInput, SendEvent 및 SendPlay예요. SendInput이 일반적으로 가장 안정적이므로, 기본적으로 Send는 SendInput과 동의어예요. SendMode를 사용해 Send가 대신 SendEvent나 SendPlay와 동의어가 되게 할 수 있어요. 문서는 SendInput과 SendPlay의 다른 장단점을 길게 설명하지만, SendInput에 문제가 있을 때 SendEvent나 SendPlay를 그냥 시도해 보라고 제안해요.
경고: SendPlay는 UI 접근 권한으로 실행하지 않으면 현대 시스템에서 잘 동작하지 않는 경향이 있어요. Windows 11 이상에서는 SendPlay가 아무 효과가 없을 수 있어요.
시도해 볼 만한 또 다른 옵션은 ControlSend예요. 이것은 공식적인 키 입력 방법을 사용하지 않고, 대신 지정한 창에 메시지를 직접 보내요. 주요 장점은 이 메시지를 받기 위해 창이 보통 활성 상태일 필요가 없다는 것이에요. 하지만 시스템의 정상적인 키보드 입력 처리를 우회하므로 때로는 동작하지 않아요.
타이밍과 지연 (Timing and delays)
때로는 인간보다 빠른 속도로 키 입력을 폭주시켜도 동작할 때가 있고, 그럴 수 없을 때도 있어요. 지연이 필요할 수 있는 상황은 일반적으로 두 가지가 있어요:
- 키 입력이 대상 응용 프로그램 안에서 어떤 변화를 트리거하기로 되어 있고(새 컨트롤이나 창을 보여주는 것 같은), 그것이 일어나기 전에 다른 키 입력을 보내면 잘못된 효과를 내는 경우.
- 응용 프로그램이 빠른 키 입력 흐름을 따라가지 못하고, 그것들을 모두 늦춰야 하는 경우.
첫 번째 경우에는 간단히 Send를 호출한 다음 Sleep, 그리고 Send를 호출하는 식으로 하면 돼요.
SetKeyDelay는 두 번째 경우를 위해 존재해요. 이 함수는 각 키 입력 사이와 키 입력의 지속 시간(키를 누르고 놓는 사이의 지연)에 수행할 지연을 설정할 수 있어요.
^1::{
SetKeyDelay 75, 25 *; 키 사이 75ms, down/up 사이 25ms.*
SendEvent "You should see the keys{bs 4}text appear gradually."
}
경고: SendInput은 키 지연을 지원하지 않으며, Send도 기본적으로 지원하지 않아요.
SetKeyDelay를 효과적으로 만들려면 보통 SendMode "Event"를 사용하거나 Send나 SendText 대신 SendEvent, SendPlay 또는 ControlSend를 호출해야 해요.
많은 텍스트 보내기 (Sending a lot of text)
여러 줄의 텍스트를 보내는 한 가지 방법은 연속 섹션(continuation section)을 사용하는 것이에요:
SendText "
(
Leading indentation is stripped out,
based on the first line.
Line breaks are kept
unless you use the ""Join"" option.
)"
일반적으로 꽤 빠르지만, SendText는 여전히 각 문자를 하나씩 보내야 하는 반면, Send는 보통 적어도 두 배 많은 메시지(key-down 그리고 key-up)를 보내야 해요. 이것은 많은 양의 텍스트를 보낼 때 눈에 띄는 지연으로 누적돼요. 지연이 길수록 사용자 입력, 키보드 포커스 이동, 또는 다른 조건 변화와 충돌할 위험이 높아지므로 불안정해질 수도 있어요.
대체로 텍스트를 클립보드에 놓고 붙여넣기(paste) 하는 것이 더 빠르고 안정적이에요. 예를 들어:
^1::{
old_clip := ClipboardAll() *; 클립보드 전체 내용 저장*
A_Clipboard := "
(Join`s
This text is placed on the clipboard,
and will be pasted below by sending Ctrl+V.
)"
Send "^v"
Sleep 500 *; Ctrl+V가 처리될 때까지 잠시 기다림*
A_Clipboard := old_clip *; 이전 클립보드 내용 복원*
}