Programing/API 2011. 8. 20. 21:45

이번에 환이매크로를 만들면서 고민햇던것이, 게임이 아닌 단순한 글을 쓸 수 있는 에딧박스라면 keybd_event함수를 이용하지않고서 SendMessageWM_CHARWM_IME_CHAR메세지만 날려주면 문자열을 입력하는 효과를 줄 수 있다. 하지만 게임에서 SendMessagePostMessage같은 함수들은 엔프로텍트나 각종 가드프로그램에서 막아버린다.
또한 막지 않는다고 해도 게임속 에딧박스의 핸들을 얻을 수 있는 방법을 찾을수가 없엇다.

따라서 게임을 창모드로 하고서 keybd_event함수를 이용하면 키입력이 가능하다는것을 알아냇다.
그래서 keybd_event 함수를 이용하여 타이핑하는 효과를 주엇더니 원하는 결과가 나왔다.
하지만 여기서 문제가 하나 발생햇는데, 영문을 타이핑할때는
keybd_event(영문의 가상키코드, 0, 0, 0); 하면 키다운메세지가 잘 전달되고 영문도 잘 찍히는데 문제는 한글에 있었다.
한글에서 "환" 이라는 글자를 보자. 저 글자를 치기위해서는 "ㅎㅗㅏㄴ"이라는 4개의 키 입력이 필요하다.
한마디로 keybd_event함수를 4번 호출해야(키업함수까지 8개) "환" 이라는 한글자가 화면에 타이핑 된다는 이야기다.

그래서 여기저기 알아본결과 한글의 자모를 유니코드상에서 분리할 수 있는 방법을 찾아냇다.
일단 알아야할것은 완성형 한글 유니코드값을 만드는 방법이다. 완성형을 만드는 방법을 알면 도식에서 초성 중성 종성을 알아내는 도식을 도출해내는것은 간단하다.

유니코드 완성형 코드
유니코드 완성형 값 = ( ( ( 초성 * 21 ) + 중성 ) * 28 ) + 종성 + 0xAC00

여기서 초성, 중성, 종성에 들어갈 값들은 다음과 같다.

초성[0~19] =
{L'ㄱ', L'ㄲ', L'ㄴ', L'ㄷ', L'ㄸ', L'ㄹ', L'ㅁ', L'ㅂ', L'ㅃ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅉ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ'};

중성[0~21] =
{L'ㅏ', L'ㅐ', L'ㅑ', L'ㅒ', L'ㅓ', L'ㅔ', L'ㅕ', L'ㅖ', L'ㅗ', L'ㅘ', L'ㅙ', L'ㅚ', L'ㅛ', L'ㅜ', L'ㅝ', L'ㅞ', L'ㅟ', L'ㅠ', L'ㅡ', L'ㅢ', L'ㅣ'};

종성[0~28] =
{L'x', L'ㄱ', L'ㄲ', L'ㄳ', L'ㄴ', L'ㄵ', L'ㄶ', L'ㄷ', L'ㄹ', L'ㄺ', L'ㄻ', L'ㄼ', L'ㄽ', L'ㄾ', L'ㄿ', L'ㅀ', L'ㅁ', L'ㅂ', L'ㅄ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ'};

여기서 종성 0번째 'x'는 종성이 존재하지 않는것을 뜻한다.

초성 중성 종성의 코드값을 알아내는 방법은 다음과 같다.

(초성인덱스) = ((유니코드 완성형 값)-0xAC00)/(28*21)
(중성인덱스) = ((유니코드 완성형 값)-0xAC00%(28*21))/28)
(종성인덱스) = ((유니코드 완성형 값)-0xAC00)%28


이것과 같은방법으로 한글유니코드의 한글자를 넣으면 자모로 분리하여 최대 3개의 값을 가지는 배열로 리턴하는 함수를 만들어 봣다.


이 함수는 HangulDisassemble(L'환');
이렇게 호출하면 {ㅎ, ㅘ, ㄴ} 이렇게 총 3의 길이를 가지는 문자열로 리턴한다.

그런데 궁극적인 목표인 keybd_event함수로 저 한글을 쓰려면 저것만으로는 할 수 없다.
저렇게 분해된 자모를 다시 키보드의 배열에 맞는 영문자로 치환해야 한다.
유니코드 한글 한글자를 인수로 주면 키보드에 있는 자모와 매칭되는 영문자문자열을 리턴하는 함수를 만들었다.




이 함수는 ReplacementHangulFragment(L'환');
이렇게 호출하면 {g, hk, s} 이렇게 총 4의 길이를 가지는 문자열로 리턴한다.
이 함수에서 중요한 부분은 ㅒ나 ㅖ와 같이 쉬프트를 누르고 써야하는 문자들은 대문자영문자로 치환하여 보여준다.

이제 한글을 영문자로 치환하는 단계까지 완료 했으니, 영문자 문자열을 인수로 주면 그 값들을 keybd_event해주는 함수를 만들어야한다.

나는 다음과 같이 만들엇는데, 내가 생각해도 많이 조잡하다.
여기서 핵심은 대문자 A~Z는 쉬프트를 누른상태에서 입력이 이루어진다는 부분이다. 한글에서도 이 부분이 없으면 원하는 결과를 얻을 수 없기때문에 꼭 필요하다. CAPSLOCK를 누르는 방법도 생각해 봣으나, 한글에서는 작동을 하지 않기 때문에 패스햇다.

소스는 다음과 같다. 인수로 영문자열 + 특수문자 + 숫자 등을 주면 그 문자열들을 그대로 타이핑 해주는 함수다.



이제 지금까지 만든 함수들을 이용하여 (영문자 + 한글 + 특수문자 + 숫자) 가 섞인 문자열을 인수로 줘도 문제없이 타이핑하는 함수를 만들어보자.
여기서 처음에 만든 한글 자모를 분리하여 리턴하는 함수는 필요가 없다. 타이핑을 하기 위해서는 영문자로 치환된값만 필요하기 때문..


이 소스에서 if( Message[i] >= 0xAC00 && Message[i] <= 0xD7A3 ) 이부분은 한글인지 검사하는 부분이다.
대충 검색해보니까 유니코드 한글범위가 저거라고 해서 걍 해봣는데 잘 되길래 놔둿다.

근데 이 함수를 만들면서 아쉬웟던점이 keybd_event 함수의 한/영키는 그때그때 상황에 따라 달라진다는 것이엇다.
그래서 imm32.lib를 추가하고 imm관련 함수들을 이용하여 조작하려 햇지만 현재 자신윈도우의 한/영 상태의 조사, 조작이 가능햇지만 다른 윈도우는 불가능했다...

그래서 임시방편으로 현재 한/영키의 상태가 [한글]상태인것으로 가정하고 영타를 쓸때는 한영키를 한번 눌러주고 쓰게 만들어 놧다.

매크로기능 하나를 추가하려고 하면 정말 힘들다.. 그런데 이러면서 많은 공부가 되는것 같다..

posted by akon47

댓글을 달아 주세요

  1.  Addr  Edit/Del  Reply 궁금

    static const int CommonNumber = Character - 0xAC00;
    여기 라인에서 Character은 뭔가요? 정의되는 부분이 없어서 에러가 발생하는데요 ㅠㅠ

    2014.03.28 18:39
  2.  Addr  Edit/Del  Reply Favicon of https://wmmu.tistory.com BlogIcon 모카쨩

    정말 소름끼치는 노가다네요;; 한글이 컴퓨터쪽에서는 골칫덩어리 언어죠 많은 공부하고 갑니다

    2016.02.18 16:28 신고
  3.  Addr  Edit/Del  Reply 엑셀 어려버

    vba 껀가요? 아님 c언어인가요?
    vba 로 이걸 쓰고 싶은데 혹시 이 코드를 vba용으로 변환할수 있을까요?

    2017.08.24 14:00
    •  Addr  Edit/Del 두리안

      저도 vba로 한글을 다른 프로그램에 타이핑 하고 싶은데 어렵네요

      2018.02.02 15:01