콘텐츠로 건너뛰기
Home » AutoHotkey 한영 상태 감지하기

AutoHotkey 한영 상태 감지하기

오토핫키에서 키보드 매크로(hot string)는 키보드의 한/영 상태를 고려하지 않고 작동하기 때문에, 한/영 상태에 따라서 다른 핫스트링을 정의해야 하는 경우가 있다. 이를 위한 함수 코드가 여러 커뮤니티나 블로그를 통해서 공유되고 있는 걸 줏어서 소개한다. (물론 구글에서 검색해보면 이 글보다는 다른 글들이 먼저 보이니까, 이 글을 보시는 분들은 아마 보셨던 코드일 것이다.)

원리는 대충 윈도 API를 통해 어떤 응용 프로그램 내의 컨트롤에 ‘메시지’를 보내어 원격으로 어떤 기능을 실행할 수 있게 하는 것이 기본적인 아이디어이다. 현재 활성화된 창에서 기본 IME의 상태창을 열도록, 응용 프로그램의 기본 IME 창에게 메시지를 보낸다. 만약 현재 한글 IME가 선택된 경우에는, 이 요청을 처리하지 못하고 에러가 반환되기 때문에 이 메시지의 결과가 실패라면 한글로 선택되어 있다고 상정할 수 있는 것이다.

따라서 이 함수는 크게 두 개의 동작으로 나눠진다.

  1. 현재 창에서 사용하는 기본 IME창의 핸들을 획득한다. (여기에 메시지를 보내야 하므로)
  2. 1에서 획득한 창에 메시지를 보낸다.

코드는 다음과 같다.

; AHK v1

IMECheckHangul()
{
  WinGetID hWnd,, A
  IMEWnd := DllCall("imm32\ImmGetDefaultIMEWnd", "UInt", hWnd, "UInt")
  Temp := A_DetectHiddenWindows
  DetectHiddenWindows ON
  SendMessage 0x0283, 0x0005, 0x0000, , ahk_id %IMEWnd%  ; 중간에 , , 로 파라미터를 하나 비워줘야 함
  Res := ErrorLevel
  if (Temp <> A_DetectHiddenWindows)
    DetectHiddenWindows %Temp%
  return Res <> 0
}

+F1::MsgBox % IMECheckHangul()

이렇게 만든 스크립트를 실행하고 <shift>F1 키를 누르면 한영 상태에 따라서 값이 메시지 박스로 표시된다. 영어일 때 0, 한글일 때 1이면 성공이다.

이 코드에서는 imm32.dll 라이브러리 파일을 열어서 함수를 호출하는데, 이 부분은 매번 호출할 때마다 라이브러리 파일을 열려고 하기 때문에, 라이브러리를 로딩해놓은 상태로 만들어놓으면 성능 향상에 도움이 될 수 있다고 한다. (별로 큰 향상은 아니지만, 루프 내에서 호출한다면 차이가 있을 수 있다.

  1. kernel32.dll 의 “LoadLibrary()” 를 사용하여 dll 파일을 로드해놓는다.
  2. 종료하기 전에 로드한 dll 파일을 해제한다.

OnExit 명령을 사용하면, 종료 시점에 호출할 함수를 지정할 수 있다. 이 함수에서 “FreeLibrary” 함수를 호출하도록 하여 로드해놓은 dll 파일을 해제해준다.

immModule := DllCall("LoadLibrary", "Str", "imm32.dll", "Ptr")

IMECheckHangul()
{
; .... 앞에서 작성한 내용
}

ExitFunc(ExitReason, ExitCode)
{
  DllCall("FreeLibrary", "Ptr", immModule)
}
OnExit("ExitFunc")

AutoHotKey 2 버전에서 작동하는 코드는 아래와 같다. 몇 가지 문법만 제외하면 거의 비슷하다. AHK2에서는 모든 명령은 내부적으로 함수로 대체되었으며, SendMessage 함수는 메시지 전송에 대한 결과를 리턴한다. 0이면 성공이고 그 외 값이면 에러 코드가 리턴된다. (AHK2에서는 ErrorLevel 변수 자체가 아예 삭제되었다.)

immModule := DllCall("LoadLibrary", "Str", "imm32.dll", "Ptr")

IMECheckHangul()
{
    hWnd := WinGetID("A")
    IMEWnd := DllCall("imm32\ImmGetDefaultIMEWnd", "UInt", hWnd, "UInt")
    temp := A_DetectHiddenWindows
    DetectHiddenWindows 1
    res := SendMessage(0x0283, 0x0005, 0x0000, , "ahk_id " IMEWnd)
    if (temp != A_DetectHiddenWindows)
        DetectHiddenWindows(temp)
    return res
}

ExitFunc(ExitReason, ExitCode)
{
  DllCall("FreeLibaray", "Ptr", immModule)
}
OnExit(ExitFunc)
0 Comments

No Comment.

%d 블로거가 이것을 좋아합니다: