한글 완성형<->조합형 변환코드 및 인코딩(EUC-KR, UTF-8, CP949)

반응형
728x90
반응형
 
 
Introduction

  이번 포스팅을 준비하는데 있어, 틈틈히 한글(인코딩)과 관련된 자료를 찾아보느라 소요시간이 많이 걸렸습니다. 본 포스팅에서 참조한 레퍼런스는 공개하도록 하겠습니다. 각 페이지에 접속하여 오래된 자료부터 천천히 하나씩 읽어보시는 것을 추천드립니다. 그 이유는 최근 자료들이 만들어지기까지 여러 블로그를 타고 다니며, 조금씩 개선된 부분도 있고 조금 이상한 부분도 있었습니다. 그래서 본 포스팅에서 다루지 못하는 내용들은 참조 링크를 확인 후 필요에 따라 추가 작업을 하시면 좋지 않을까 합니다. 
  그럼 본 포스팅의 최종 목적은 "인코딩에 문제 없이 코딩하고 싶다." 입니다. 그래서 iOS, Android, Windows, macOS 등에서 자유롭게 데이터를 주고 받고 싶은것이 목적입니다. 물론 각 플랫폼마다 통신을 주고 받는 방법은 조금만(?) 찾아보면 자료들이 많이 나옵니다. 문제는 한글인데, 한글을 보내면 이상한 외계어로 전달되어버리기 때문입니다. 작업을 하다 너무 싫어서 각각의 플랫폼에 맞춰 인코딩 작업을 할 수 있는 방편을 모두 만들계획입니다. 소스공개는 고민 후 진행하도록 하겠습니다. 본 포스팅의 목차는 다음 파트를 확인 후 원하시는 부분을 찾아 보시면 됩니다. 
 
그럼 시작해볼까요? 
 
 
Goal

  • 문제점
    • Socket TCP통신을 할 경우 한글 글자 깨짐 문제 
      • swift <-> Windows C/C++ 
  • Goal
    • 인코딩이란?
      • macos: UTF-8 NFD
      • Windows: UTF-8 NFC
      • 유니코드
      • EUC-KR
      • UTF-8
      • CP949
    • 한글의 조합형/완성형에 대해 이해하기 
      • 한글 자모 분해 (수식&소스코드)
      • 한글 자모 합치기 (수식&소스코드)
    • 활용방안
      • 한글 천지인
      • 보안 키보드
  • 기타 생각해볼 점
    • 글자 입력기를 이용하여 해킹할 수 있는 방법 Idea?
 
 
Index

  • 글자조합방식: 조합형 및 완성형은 어떤 것일까?
  • 한글 유니코드의 초성/중성/종성 분리 및 결합방법
    • 참고자료 Windows API 정복 : 도서 유니코드 요약 
  • [C/C++/API/MFC] 기반에서의 한글 변환 코드-01
  • [C/C++/API/MFC] 기반에서의 한글 변환 코드-02
  • [C/C++/API/MFC] 기반에서의 한글 변환 코드-03
    • #코드: 한글 입력시 초성, 중성, 종성 분리 
    • #코드 : 한글 입력시 영문 문자열로 리턴
    • #코드 : 영문 입력시 한글 문자열로 리턴
    • #코드 : [영문+한글+특수문자+숫자] 입력시 한글 문자열로 리턴
  • [C/C++/API/MFC] 기반에서의 한글 변환 코드-04
  • Reference
 

 

 

 
인코딩이란?

 
  먼저 macos(UTF-8 NFD)에 대한 자료를 검색해보니 잘정리되어있는 자료가 있어 필요한 부분만 가져오고 나머지는 링크를 이용하여 참조해주시기 바랍니다.  [참고: 한글인코딩이란]
 
  • NFC(Normalization Form Composition)
    • GNU/Linux
    • Windows 
 
설명이 어려워 조금 쉽게 말하자면 다음과 같습니다. 유니코드형태의 완성형으로 저장을 한다고 보시면 됩니다. 
 
  • NFD(Normalization Form Decomposition)
    • macOS
 
NFD의 경우, 자음과 모음을 분리하여 저장합니다. 즉 조합형의 글자처럼 저장하되 합쳐진 글자가 아닌 분리된 형태로 초성/중성/종성을 저장합니다. 
 
  • UTF-8 : 유니코드를 위한 인코딩 방식
    • Linux, php, mySQL 등 사용
 
  • EUC-KR, CP949
    • 웹에서 자주 사용하는 완성형(CP949는 MS에서 사용하는 완성형)
 
 
아래 내용들을 다 정리하고 보니, 그럼 무엇이 필요한걸까? 인코딩 normalization 하는 모듈이 필요한 것이 아닐까? 통신과 관련된 작업을 수행할 때 항상 인코딩 문제가 발생할 수 밖에 없다. 이럴 때는 하나의 인코딩형태로 변환하면 끝이지만, 문제는 각 시스템 마다 사용하는 인코딩이 다르기때문에 데이터를 주고 받을 때만 꼭 인코딩/디코딩을 통해 통신을 해야한다. 이를 위해, 기초가 되는 한글의 조합형/완성형을 알아두는 것이 좋은 방법이 아닐까 생각된다. 그리고 한글 외 일본어/중국어/독일어 등 영어를 제외한 다른 언어들에서도 문제가 되기때문에 이번 문제만 해결하게 되면 다른 언어에서도 큰 문제 없이 해결 될 것이라 생각된다. 
 
 
글자 조합 방식

 
조합형&완성형 그림참조 : [2014.11.27 한글 인코딩 방식 이해]
 
한글은 조합형 완성형으로 사용되고 있습니다. 조합형 자음과 모음을 이용하여 글자를 조합하는 것으로서 초성, 중성, 종성으로 구성되어있습니다.  완성형은 "하나의 완성되어있는 글자" 로서 초,중,종성이 아닌 "" 혹은 "", "" 처럼 되어있습니다. 블로그의 내용에 따르면 오래된 한글의 표현방식으로서 완성형 문자표에 나타나지 않은 글자는 "" 등의 형태로 표기가 된다고 합니다.  [2014.11.27 한글 인코딩 방식 이해]
 
이어, 조합형이 한글을 표현하는데 있어 가장 확장성이 좋다고하지만, 윈도우의 기본 인코딩 방식은 "CP949 완성형"이라고 합니다.  CP949는 무엇인지 알아볼까요? [UTF-8, EUC-KR, CP949]
 
[UTF-8]
  • 개발자들이 원하는 방식(대부분 서버 운용체제/웹 서버/코딩 등에서 사용)
  • 조합형 유니코드 인코딩 방식 사용
  • ASCII 문자들을 표현 할 수 있음
  • 초성, 중성, 종성을 각각 1바이트로 인식하여 한글을 총 3바이트로 인식함
  • 공백,영문은 1바이트로 인식
  • 유니코드의 경우, 다른 국가에서 한글 언어팩이 설치되지 않아도 한글 표현이 가능함(외국어 표현 가능)
 
[EUC-KR, CP949 (MS949)]
  • EUC-KR의 경우는 웹에서 사용
    • 완성현 인코딩 방식(2바이트)
    • 한글을 사용하는 곳에서만 제대로 문자가 보이는 단점
    • 한글과 영어만 사용하는 페이지에서 적합
  • CP949(MS949) 윈도우에서 사용
    • 완성현 인코딩 방식(2바이트)
    • MS사가 도입
 
[참고자료]
 
상위 참고자료에는 위키백과에 유니코드의 글자가 어떻게 구성되어있는지 표로 나타나 있습니다. 
 

 

 

 
한글 유니코드 초성/중성/종성 분리 및 결합

 
대부분의 자료를 살펴보면 유니코드에서 한글(Wiki참조)이 어떻게 구성되어있는지 정리되어있습니다. 한글을 나타내는 유니코드는 초성, 중성, 종성으로 구성되어있고 각각의 세부내용을 살펴보면 다음과 같이 구성되어있습니다. 유니코드의 Table 참조(자모, 음절)
 
초성(19개)
'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
 
중성(21개)
'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'
 
종성(28개)
공백(' '),'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
(※ 종성 첫번째 글자는 공백(' ') 입니다. 
 
그래서 조합형의 총 글자 수는 11172자(=19 x 21 x 28) 입니다. 
 
#한글(유니코드)을 초성/중성/종성으로 분리하는 수식
 
[1]
초성 = ( ( (characterValue - 종성 ) / 28 ) - 중성 ) / 21
중성 = ( (characterValue - 종성 ) / 28 ) % 21
종성 = characterValue % 28
( 초성 : 0x1100   , 중성 : 0x1161   , 종성 : 0x11A7 )
 
[3]
(초성인덱스) = ((유니코드 완성형 값)-0xAC00)/(28*21)
(중성인덱스) = ((유니코드 완성형 값)-0xAC00%(28*21))/28)
(종성인덱스) = ((유니코드 완성형 값)-0xAC00)%28
 
 
#초성/중성/종성을 이용하여 한글(유니코드) 결합
 
글자를 조합하기위해서는 초기 한글 코드 값에 초성/중성/종성의 값을 더하면 됩니다. 최종수식은 다음과 같습니다. 참조한 페이지에서는 수식이 조금 달라서 둘다 표기를 하니 참고하시기 바랍니다. 
 
[1] 한글 = 44032(한글 코드 테이블의 첫번째 문자코드번호) + (초성 * 588) + (중성 * 28) + 종성
[2] 한글 = BASE_CODE(한글코드 테이블의 첫번째 문자코드) + 초성 * 21 * 28 + (중성 - 19) * 28 + (종성 - 40)
[3] 한글 =  ( ( ( 초성 * 21 ) + 중성 ) * 28 ) + 종성 + 0xAC00
 
각각의 자료는 포스팅을 하신 분들의 내용을 살펴보시는 것이 혼돈되지 않을까 생각됩니다. 자료 검토할 때, 항상 고민되지만 실제 사용되는 코드를 보게되면 그제서야 이해가 되죠. 
 
 
아래는 간단하게 한글로 구성된 코드도 있으니 참고 하시기 바랍니다. 
한글_베이스 U+AC00
중성_경우의_수 21
종성_경우의_수 28
 
함수 자소합치기(초성, 중성, 종성)
{
    완성형글자 = 한글베이스 + (초성 * 중성_경우의_수 * 종성_경우의_수) + (중성 * 종성_경우의 수) + 종성;
}
 
함수 자소나누기(완성형글자)
{
    초성 = (완성형글자 - 한글_베이스) / (중성_경우의_수 * 종성_경우의_수);
    중성 = (완성형글자 - 한글_베이스) % (중성_경우의_수 * 종성_경우의_수) / 종성_경우의_수;
    종성 = (완성형글자 - 한글_베이스) % 종성_경우의_수;
}
 
 
그 외에 위키백과-한글을 찾아보면 다음과 같은 내용도 있으니 참고하면 좋을 듯 하네요. 
 
 
 
 
 
[Windows API 정복] 도서 유니코드 요약

 
  • SBCS(Single Byte Character Set)
    • 아스키 문자셋이나 ANSI 문자셋처럼 한 바이트로 한 문자를 표현하는 문자 코드
    • 최대 256개 문자 표현 가능
    • 미국의 문자에만 맞게 작성되어 독일어, 불어 등의 특별한 기호를 가진 문자를 표현하기에 부족함 
  • DBCS(Double Byte Character Set)
    • 영문기호는 8비트로 표현
    • 한글은 16비트로 표현하는 ANSI의 확장형 문자 코드
 
#DBCS 예시 "럭키 Seoul"
  • 7개의 문자로 이루어져 있지만, 배열의 크기는 9바이트
    • 문자의 개수를 정확하게 알 수 없음
    • IsDBCSLeadByte() 함수를 이용하여 확인 가능
    • CharPrev(), CharNExt() 함수도 사용가능하나 비효율적으로 권장하지 않음
 
#유니코드 예시 "럭키 Seoul"
  • 한글/영문 모두 2바이트
  • Windows 95/98 에서는 유니코드 미지원으로 사용 불가(허걱)
 
#Windows API에서의 정의
 
typedef wchar_t WCHAR;     // unicode
typedef char CHAR;         // ANSI
 
  • WCHAR(=unsigned short int) 
#ifdef UNICODE
    typedef WCHAR    TCHAR;
#else
    typedef char     TCHAR;
#endif
 
 
UNICODE 정의에 따라 타입이 변경됨
 
기타 정의된 내용은 아래와 같음.
 
typedef WCHAR          *PWCHAR, *LPWSTR, *PWSTR;
typedef CONST WCHAR    *LPCWCH, *LPCWSTR, *PCWSTR;
typedef CHAR           *PCHAR, *LPSTR, *PSTR;
typedef CONST CHAR     *LPCCH, *LPCSTR, *PCSTR;
 
이를 정리하면 다음과 같이 됨.
 
 
그 외에 TextOut 함수의 변형된 함수가 아래와 같이 있음.
 
ifdef UNICODE
#define TExtOut TextOutW    // Unicode(Wide)
#else
#define TextOut TextOutA             // ANSI
#endif
 
이런 함수는 TextOutA()함수는 내부적으로 ANSI에서 유니코드로 변환 후  TextOutW() 함수를 수행함. 
 
그리고 strlen, wcslen, lstrlen, lstrcpy, lstrcat, lstrcmp 등 함수 변환관계를 알아둬야 함.
 
ANSI <-> UNICODE 변환 코드 참조
 
int MultiByteToWideChar( UINT CodePage,  DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar );


int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar );


size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );


size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );

CA2W()
CW2CA()
T2A()
T2W()
 
그리고 MFC등을 사용하면서 쓰는 CString을 포함하여, std::string, std;;wstring 간의 변환은 블로그를 참조하여 개발하면 됨.
 

 

 

 
 
[C/C++/API/MFC] 기반에서의 한글 변환 코드-01

 
#공식
 
nChar = Unicode - 0xAC00;
초성: index = nChar / (0x0015 * 0x001C);
중성: index = (nChar / 0x001C) % 0x0015;
종성: index = nChar % 0x001C;
 
 
#코드
#include <locale.h>
#include <stdio.h>
#include <windows.h>
 
int main(void)
{
 setlocale(LC_ALL, "Korean");
 WORD in_char, in_cho, in_jung, in_jong;
 WORD result;
 
 printf("Input a letter : ");
 wscanf(L"%c", &in_char);
  
 // 초`중`종성 분해
 in_char = in_char - 0xAC00;
 //in_cho = in_char / (21 * 28);
 in_cho = in_char / (0x0015 * 0x001C);
 //in_jung = (in_char / 28) % 21;
 in_jung = (in_char / 0x001C) % 0x0015;
 //in_jong = in_char % 28;
 in_jong = in_char % 0x001C;
 
 
 // 초`중`종성 print
 if ( in_jong == 0 )
  wprintf(L"%c => %c + %c\n", in_char + 0xAC00, in_cho + 0x1100, in_jung + 0x1161);
 else
  wprintf(L"%c => %c + %c + %c\n", in_char + 0xAC00, in_cho + 0x1100, in_jung + 0x1161, in_jong + 0x11A7);
}
 
 
 
 
[C/C++/API/MFC] 기반에서의 한글 변환 코드-02

 
#코드
 
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>
#include <stdbool.h>
 
static const char * const initial_array[] = {
"ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ",
"ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"
};
static const char * const medial_array[] = {
"ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ",
"ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ",
"ㅣ"
};
static const char * const final_array[] = {
"", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ",
"ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ",
"ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"
};
 
#define count_elements_of(array) (sizeof(array)/sizeof(array[0]))
 
static _Bool DecomposeKoreanSyllable(wchar_t code, wchar_t *initial, wchar_t *medial, wchar_t *final){
const wchar_t num_initial = count_elements_of(initial_array);
const wchar_t num_medial = count_elements_of(medial_array);
const wchar_t num_final = count_elements_of(final_array);
const wchar_t begin = 0xAC00;
const wchar_t end = begin + num_initial * num_medial * num_final;
 
if(begin <= code && code < end){
code -= begin;
if(final)*final = code % num_final;
code /= num_final;
if(medial)*medial = code % num_medial;
code /= num_medial;
if(initial)*initial = code;
return true;
}
else return false;
}
 
int main(void){
char buf[80];
setlocale(LC_ALL, "");
mbtowc(0, 0, 0); // reset
 
while(fgets(buf, sizeof(buf), stdin)){
size_t buf_offset = 0, buf_len = strlen(buf);
wchar_t wc;
int wc_len;
while((wc_len = mbtowc(&wc, buf + buf_offset, buf_len - buf_offset)) > 0){
wchar_t initial, medial, final;
if(DecomposeKoreanSyllable(wc, &initial, &medial, &final)){
fputs(initial_array[initial], stdout);
fputs(medial_array[medial], stdout);
fputs(final_array[final], stdout);
}
buf_offset += wc_len;
}
}
putchar('\n');
return 0;
}
 
 

 

 

 
 
[C/C++/API/MFC] 기반에서의 한글 변환 코드-03

 
#코드: 한글 입력시 초성, 중성, 종성 분리 
 
TCHAR* HangulDisassemble(TCHAR Character)
{
    static const TCHAR Chosung[19]={L'ㄱ', L'ㄲ', L'ㄴ', L'ㄷ', L'ㄸ', L'ㄹ', L'ㅁ', L'ㅂ', L'ㅃ', L'ㅅ', L'ㅆ', L'ㅇ', L'ㅈ', L'ㅉ', L'ㅊ', L'ㅋ', L'ㅌ', L'ㅍ', L'ㅎ'};
    static const TCHAR Joongsung[21]={L'ㅏ', L'ㅐ', L'ㅑ', L'ㅒ', L'ㅓ', L'ㅔ', L'ㅕ', L'ㅖ', L'ㅗ', L'ㅘ', L'ㅙ', L'ㅚ', L'ㅛ', L'ㅜ', L'ㅝ', L'ㅞ', L'ㅟ', L'ㅠ', L'ㅡ', L'ㅢ', L'ㅣ'};
    static const TCHAR Jongsung[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'ㅎ'};
    static const int CommonNumber=Character-0xAC00;
    static TCHAR Fragment[4];

    int ChosungIndex=(int)(CommonNumber/(28*21));
    int JoongsungIndex=(int)((CommonNumber%(28*21))/28);
    int JongsungIndex=(int)(CommonNumber%28);

    Fragment[0] = Chosung[ChosungIndex];
    Fragment[1] = Joongsung[JoongsungIndex];
    Fragment[2] = Jongsung[JongsungIndex];
    Fragment[3] = L'\0';
    return Fragment;
}
 
#사용방법
 
TCHAR *pList = HangulDisassemble(L"글");

// pList { ㄱ, ㅡ, ㄹ } 포함
 
 
#코드 : 한글 입력시 영문 문자열로 리턴
 
TCHAR* ReplacementHangulFragment(TCHAR Character)
{
    static const TCHAR Chosung[19][3]={{L"r"}, {L"R"}, {L"s"}, {L"e"}, {L"E"}, {L"f"}, {L"a"}, {L"q"}, {L"Q"}, {L"t"}, {L"T"}, {L"d"}, {L"w"}, {L"W"}, {L"c"}, {L"z"}, {L"x"}, {L"v"}, {L"g"}};

    static const TCHAR Joongsung[21][3]={{L"k"}, {L"o"}, {L"i"}, {L"O"}, {L"j"}, {L"p"}, {L"u"}, {L"P"}, {L"h"}, {L"hk"}, {L"ho"}, {L"hl"}, {L"y"}, {L"n"}, {L"nj"}, {L"np"}, {L"nl"}, {L"b"}, {L"m"}, {L"ml"}, {L"l"}};

    static const TCHAR Jongsung[28][3]={{L" "}, {L"r"}, {L"R"}, {L"rt"}, {L"s"}, {L"sw"}, {L"sg"}, {L"e"}, {L"f"}, {L"fr"}, {L"fa"}, {L"fq"}, {L"ft"}, {L"fx"}, {L"fv"}, {L"fg"}, {L"a"}, {L"q"}, {L"qt"}, {L"t"}, {L"T"}, {L"d"}, {L"w"}, {L"c"}, {L"z"}, {L"x"}, {L"v"}, {L"g"}};

    const int CommonNumber=Character-0xAC00;
    static TCHAR ReplacementFragment[10];

    int ChosungIndex=(int)(CommonNumber/(28*21));
    int JoongsungIndex=(int)((CommonNumber%(28*21))/28);
    int JongsungIndex=(int)(CommonNumber%28);

    wcscpy(ReplacementFragment, Chosung[ChosungIndex]);
    wcscat(ReplacementFragment, Joongsung[JoongsungIndex]);
    if( JongsungIndex != 0 )
    {
        wcscat(ReplacementFragment, Jongsung[JongsungIndex]);
    }
    return ReplacementFragment;
}
 
#사용방법
 
TCHAR *pList = HangulDisassemble(L"글");


// pList { r, m, f } 포함
 
 
#코드 : 영문 입력시 한글 문자열로 리턴
 
void TypingEnglish(TCHAR* Message)
{
    TCHAR NumSpecialChar[11]=L")!@#$%^&*(";
    TCHAR SpecialChar[12]=L"`-=\\[];',./";
    TCHAR ShiftSpecialChar[12]=L"~_+|{}:\"<>?";
    BYTE SpecialCharCode[11]={0xC0, 0xBD, 0xBB, 0xDC, 0xDB, 0xDD, 0xBA, 0xDE, 0xBC, 0xBE, 0xBF};

    int Length=wcslen(Message);

    for(int i=0; i<Length; i++) 
    {
        if( Message[i] >= L'a' && Message[i] <= L'z' )
        {
            keybd_event((BYTE)Message[i]-L'a'+L'A', 0, 0, 0);
            keybd_event((BYTE)Message[i]-L'a'+L'A', 0, KEYEVENTF_KEYUP, 0);
        }
        else if( Message[i] >= L'A' && Message[i] <= L'Z' )
        {
            keybd_event(VK_SHIFT, 0, 0, 0);
            keybd_event((BYTE)Message[i], 0, 0, 0);
            keybd_event((BYTE)Message[i], 0, KEYEVENTF_KEYUP, 0);
            keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
        }
        else if( Message[i] >= L'0' && Message[i] <= L'9' )
        {
            keybd_event((BYTE)Message[i], 0, 0, 0);
            keybd_event((BYTE)Message[i], 0, KEYEVENTF_KEYUP, 0);
        }
        else if( Message[i] == L' ' )
        {
            keybd_event((BYTE)Message[i], 0, 0, 0);
            keybd_event((BYTE)Message[i], 0, KEYEVENTF_KEYUP, 0);
        }
        else
        {
            for(int j=0; j<10; j++)
            {
                if( Message[i] == NumSpecialChar[j] )
                {
                    keybd_event(VK_SHIFT, 0, 0, 0);
                    keybd_event(L'0'+j, 0, 0, 0);
                    keybd_event(L'0'+j, 0, KEYEVENTF_KEYUP, 0);
                    keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
                    break;
                }
                if( j == 9 )
                {
                    for(int k=0; k<11; k++)
                    {
                        if( Message[i] == SpecialChar[k] )
                        {
                            keybd_event(SpecialCharCode[k], 0, 0, 0);
                            keybd_event(SpecialCharCode[k], 0, KEYEVENTF_KEYUP, 0);
                            break;
                        }
                        else if( Message[i] == ShiftSpecialChar[k] )
                        {
                            keybd_event(VK_SHIFT, 0, 0, 0);
                            keybd_event(SpecialCharCode[k], 0, 0, 0);
                            keybd_event(SpecialCharCode[k], 0, KEYEVENTF_KEYUP, 0);
                            keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
                            break;
                        }
                    }
                }
            }
        }
    }
}
 
 
#코드 : [영문+한글+특수문자+숫자] 입력시 한글 문자열로 리턴
 
void TypingMessage(TCHAR* Message)
{
    static TCHAR Buf[10];
    int Length=wcslen(Message);

    for(int i=0; i<Length; i++)
    {
        if( Message[i] >= 0xAC00 && Message[i] <= 0xD7A3 ) // 한글 범위 검사
        {
            wcscpy(Buf, ReplacementHangulFragment(Message[i]));
            TypingEnglish(Buf);
        }
        else
        {
            Buf[0] = Message[i];
            Buf[1] = L'\0';
            keybd_event(VK_HANGEUL, MapVirtualKey(VK_HANGEUL, 0), 0, 0);
            keybd_event(VK_HANGEUL, MapVirtualKey(VK_HANGEUL, 0), KEYEVENTF_KEYUP, 0);
            TypingEnglish(Buf);
            keybd_event(VK_HANGEUL, MapVirtualKey(VK_HANGEUL, 0), 0, 0);
            keybd_event(VK_HANGEUL, MapVirtualKey(VK_HANGEUL, 0), KEYEVENTF_KEYUP, 0);
        }
    }
}
 
 
 
 

 

 

 
 
[C/C++/API/MFC] 기반에서의 한글 변환 코드-04

 
#코드
 
#include "stdafx.h"
#include <iostream>
#include <locale>
int start[3] = {0x1100, 0x1161, 0x11A8 - 1};
int value, cho, jung, jong;
bool extract(wchar_t *str)
{
    // 변수 초기화
    value = cho = jung = jong = 0;
    // 문자열 검사 (한글만 입력되었는가?)
    for(int i = 0; i<wcslen(str); i++)
    {
        // 유니코드 한글 문자열 범위 검사 (0xAC00 ~ 0xD7A3)
        if(str[i] < 0xAC00 || str[i] > 0xD7A3)    {
            if(str[i] == 0x20) continue;
            return false;
        }
    }
        
    for(int i = 0; i<wcslen(str); i++)
    {
        // 공백 검사
        if(str[i] == 0x20) {
            wprintf(L" ");    continue;
        }
        value = str[i] - 0xAC00;
        jong = value % 28;
        jung = ((value - jong) / 28) % 21;
        cho = ((value - jong) / 28 ) / 21;
        if(jong == 0x11A8) jong = 0;    
        cho += start[0]; jung += start[1]; jong += start[2];
        wprintf(L"%c %c %c", cho, jung, (jong == 0x11A8-1) ? NULL : jong);
    }
    printf("\n\n");
    return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_ALL, "Korean");
    wchar_t str[] = L"급할수록 돌아가라";
    wprintf(L"입력 : %s\n변환 : ", str);
    if(!extract(str))
        printf("한글 문자만 입력이 가능합니다\n");
    return 0;
}
 
사용시 결과 
 
입력 : 급할수록 돌아가라
변환 : ㄱ ㅡ ㅂ ㅎ ㅏ ㄹ ㅅ ㅜ ㄹ ㅗ ㄱ ㄷ ㅗ ㄹ ㅇ ㅏ ㄱ ㅏ ㄹ ㅏ 
 
 
 
 
기타 생각해볼 내용

 
(구글링 통한 캡쳐)
 
위아래 레퍼런스 자료를 살펴보면, 한글 천지인과 관련된 내용이 있습니다. 천지인을 보면서 왜 글자 자판이 저렇게 되었는지 궁금하지 않던가요? 아래 오토마타 관련 포스팅을 참조하시면 궁금증이 해결됩니다. 하지만, 개발에 있어서 최적화된 작업을 위해 이렇게 개발을 하였지만 사용하는 사용자 입장에서는 조금 더 편리하게 개발 할 수 있지 않을까요? 내부 구조를 살펴보고나서야 이해되는 문제지만, 사용자 입장에서는 익숙하지 않다면 많은 문제들이 발생하게 됩니다. 나중에 천지인과 관련한 부분은 고민해보고 새로운 키보드를 만들어볼까 합니다. (언제가될지는...)
 
두번째로는 은행에서 사용하는 보안 키보드입니다. 천지인을 응용하여 만든 것이겠죠? 위치만 다를 뿐 글자의 조합은 동일하니깐요. 
 
세번째로는 최근 카카오톡(광고제거/도배기) 활용하기라는 포스팅을 하였습니다.  Win32 API를 이용하여 메시지를 보낼 수 있는 만큼, 반대로 카카오톡의 채팅창에 입력되는 글자를 그대로 가지고 올 수 있지 않을까요? 물론 사용자가 입력하는 글자를 분석 혹은 검색해야하는 부분이 있지만 가능한 부분이라 생각됩니다. 하지만, 네트워크가 연결된 부분에 있어서는 IP흔적이 남기때문에 심심해서라도 하지말길 바랍니다. 
 
 
 
마무리 

포스팅이 길어지면서 내용이 다소 이어지지 않는 점은 있지만 1차 마무리를 지어야 추후 내용의 추가 혹은 수정이 가능 할 것 같아 부족한 포스팅으로 마무리를 하려 합니다.  한글 인코딩 작업 포스팅에 본 블로그를 보고 작업한 최종결과물이 있습니다. (소스코드 없음) 원하는 인코딩 작업은 해결이 완료되어 이제 목적을 가지고 최종 결과물을 취합 및 개발 시작하려고 합니다. 걱정이 많은 작업이였는데, 그래도 어찌어찌 끝나 다행이란 생각합니다. 
앞으로 좋은 결과물을 블로그에 업로드 할 수 있길. 기대해주시기 바랍니다. 
 
 
Reference 

 
 
 
 
 
 
 
 
 
반응형

이 글을 공유하기

댓글(0)

Designed by JB FACTORY