블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2797)
Unity3D (853)
Programming (479)
Python (8)
TinyXML (5)
STL (13)
D3D (3)
MFC (1)
C/C++ (54)
C++/CLI (45)
C# (251)
WinForm (6)
WPF (5)
Math (10)
A.I. (1)
Win32API (11)
Algorithm (3)
Design Pattern (7)
UML (1)
MaxScript (1)
FMOD (4)
FX Studio (1)
Lua (2)
Terrain (1)
Shader (3)
boost (2)
Xml (2)
JSON (4)
Etc (11)
Monad (1)
Html5 (4)
Qt (1)
Houdini (0)
Regex (14)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (61)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

GetAsyncKeyState() 함수와 GetKeyState() 함수는 키보드의 키가 눌렸는지를 체크하는 함수들이다.

GetAsyncKeyState() 함수는 비 동기(Asynchronism)로 처리한다. 즉, 호출된 시점에서 키 상태를 조사하여, 메시지 큐를 거치지 않고 바로 리턴을 해 주므로 키 입력을 바로 처리해 줄 수가 있다.

GetKeyState() 함수는 호출된 시점에서 메시지 큐를 거치며, 메시지 발생 후의 상태를 리턴하게 되므로, 키보드 메시지 처리 루틴내에서 사용해야 한다. 게임과 같이 키 입력에 바로 반응을 해 줘야 하는 프로그램에서는 GetAsyncKeyState()함수를 사용하는 편이 좋다.

GetAsyncKeyState() 함수의 사용은

[code]if ( GetAsyncKeyState(VK_RETURN) )        // enter 키가 눌렀다면
// 처리            }
[/code]

이렇게 직접 쓰여도 되지만, 아래와 같은 형식으로 많이 사용한다.

[code]if ( GetAsyncKeyState(VK_RETURN) & 0x8000 )         // enter 키가 눌렀다면
// 처리            }
[/code]

왜? 0x8000으로 AND 연산을 통하여 키 눌림을 체크할까?

GetAsyncKeyState() 함수는, 키가 눌려진 시점에서 0x8000 값을 리턴해 준다. 그리고 함수가 호출되었을때 키가 눌려져 있었다고 0x0001 값을 리턴해 준다. 즉, 0x8000 은 현재 키가 눌려진 상태를 뜻하고, 0x0001은 지난번 호출과 이번 호출 사이에 키가 눌려진 적이 있었다 라는 것을 뜻한다.

예를 들어, 아래 방향키가 게임내에서 비행기도 움직이고, 메뉴에서 위아래 선택에도 쓰인다고 가정해 보자. AND 연산없이 그냥 사용하여 비행기를 움직이다가, F1키를 눌러 메뉴를 띄웠을 때 커서가 자동으로 아래쪽으로 내려갈 위험성이 생긴다. 왜냐하면, F1키를 누르는 시점에서 - if ( GetAsyncKeyState(VK_F1) ) - VK_DOWN은 눌리지 않았지만 리턴값이 0x0001이 되어 if ( GetAsyncKeyState(VK_F1) ) 전에 호출된 if ( GetAsyncKeyState(VK_DOWN) ) 이 참이 되기 때문이다. 하지만, 0x8000으로 AND 연산을 하면,

   1000 0000 0000 0000 (키눌림 0x8000)                0000 0000 0000 0001 (눌러진 적이 있음 0x0001)
& 1000 0000 0000 0000 (AND 연산 0x8000)         & 1000 0000 0000 0000 (AND 연산 0x8000)
---------------------------------------       -----------------------------------------------
   1000 0000 0000 0000 (키눌림 0x8000)                0000 0000 0000 0000 (키 안 눌림)

위와 같은 결과가 되어, 정확한 시점에서 키가 눌러진 상태를 체크할 수가 있는 것이다. 즉, 정확한 시점에서 키눌림 상태를 체크하기 위해서 0x8000으로 AND 연산을 해 주는 것이다.

 

GetKeyState() 함수의 사용 예

[code]// 키보드 메시지 처리루틴이 있는 콜백 함수 내에서...
// char szTemp[256];

case WM_KEYDOWN:
        // Ctrl + 왼쪽 화살표키가 눌렸는지 조사
        if ( wParam == VK_LEFT ) && (GetKeyState(VK_CONTROL) < 0) )
        {
                wsprintf(szTemp, "Ctrl키와 왼쪽 화살표 키가 눌림");
        }
        return 0;
[/code]

GetKeyState() 함수의 리턴값이 음수일 경우는 해당키가 눌린 상태이고, 음수가 아닐 경우는 해당키가 눌리지 않은 상태이다.

GetAsyncKeyState와 GetKeyState는 둘 다 키의 상태값을 알아내는 함수이다. 하지만 이 둘 사이에는 차이점이 있는데 다음과 같은 것들이다.

GetAsyncKeyState는 "키가 눌렸는가?"와 "언제부터 눌렸는가?"를 알아낼 때 사용한다. 키가 눌렸을 때 GetAsyncKeyState는 0x8000 bit가 1이된다. 그리고, 이전에 GetAsyncKeyState가 호출되었을 때부터 이번에 GetAsyncKeyState가 호출될 때까지 중간에 끊기지 않고 계속 눌려있는 상태라면 0x0001 bit는 0이 되고, 그렇지 않은 경우는 1이 된다.

1) CTRL 키가 눌린 상태이다.
2) GetAsyncKeyState(VK_CONTROL)를 호출하면 0x8001을 리턴한다.
3) GetAsycnKeyState(VK_CONTROL)을 한번 더 호출하면 0x8000을 리턴한다.

1) CTRL 키가 눌린 상태이다.
2) GetAsyncKeyState(VK_CONTROL)를 호출하면 0x8001을 리턴한다.
3) CTRL 키를 뗬다가 다시 눌렸다.
4) GetAsycnKeyState(VK_CONTROL)을 한번 더 호출해도 0x8001을 리턴한다.

키가 눌리지 않았을 때, GetAsyncKeyState는 항상 0x0000을 리턴한다.


GetKeyState는 "키가 눌렸는가?"와 "키의 토글상태가 무엇인가?"를 알아낼 때 사용한다. 키의 토글 상태란 Caps Lock, Num Lock의 키가 한번 누르면 불이 켜지고 다시 한번 누르면 불이 꺼지는 것을 생각하면 이해가 빠를것 같다.
키보드 상에는 위에서 말한 키만 불이 켜졌다 꺼졌다하면서 토글상태를 알려주고 있지만 다른 키들도 토글 상태를 갖고 있으며 단지 우리 눈에 보이지 않을 뿐이다. 이 토글 상태를 GetKeyState 함수로 알아낼 수 있다.

GetKeyState의 리턴값은 SHORT가 아닌 CHAR로 생각된다.
리턴값을 살펴보면 0xffffff81, 0xffffff80, 0x00000001, 0x00000000이 되는 것을 볼 수 있기 때문이다.
참고로 같은 SHORT형을 리턴하는 GetAsyncKeyState의 리턴값은 다음과 같다.
0xffff8001, 0xffff8000, 0x00000000 셋 중 하나

** MSDN에는 현재 하드웨어(키보드)의 상태값을 알아내길 원한다면 GetAsyncKeyState를 사용하라고 나와있다. GetKeyState는 메시지큐에 저장된 메시지에 따라 값이 변하기 때문이다.
메시지큐에 처리되지 않은 CTRL키가 눌렸다는 메시지가 쌓여있을 때,사용자가 CTRL키를 더이상 누르지 않고 있다면. GetAsyncKeyState는 "키가 눌리지 않았음"을, GetKeyState는 "키가 눌렸음"을 리턴할 것이다.



출처 : http://www.silverwolf.co.kr/4842

반응형

'Programming > Win32API' 카테고리의 다른 글

윈도우 투명  (0) 2011.10.30
한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
Posted by blueasa
, |

윈도우 투명

Programming/Win32API / 2011. 10. 30. 19:07
반응형

'Programming > Win32API' 카테고리의 다른 글

GetAsyncKeyState() 함수와 GetKeyState() 함수의 차이  (0) 2012.06.25
한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
Posted by blueasa
, |

한영 변환키 누름 상태는 윈도 메세지에서 WM_IME_NOTIFY 로 확인하는 방법과

WM_KEYUP 이나 WM_KEYDOWN 에서 wParam 에 VK_PROCESSKEY 가

들어오는것으로 확인 할 수 있다.

다만 키를 한번만 누르더라도 WM_IME_NOTIFY 로는 메세지가 여러개가 오는데,

그 중 wParam 이 IMN_SETCONVERSIONMODE 로 한번 오며 이것으로 채크하면 되겠다.

이 중 VK_PROCESSKEY 을 확인하는 방법으로 해 놓았었는데, 이것이 일부 노트북에서

동작하지 않는 것을 발견했다.

2개의 노트북에서 그런 현상이 발견되었으며 그 중 한대를 디버깅 해보았다.

한영키를 누를시 메세지에서 WM_KEYUP 이나 WM_KEYDOWN 은 넘어 오지 않고

WM_IME_NOTIFY 만 넘어오는 것이다.

이런 현상을 놓고 보았을때 WM_IME_NOTIFY 로 확인하는것이 맞겠다.
반응형

'Programming > Win32API' 카테고리의 다른 글

GetAsyncKeyState() 함수와 GetKeyState() 함수의 차이  (0) 2012.06.25
윈도우 투명  (0) 2011.10.30
Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
Posted by blueasa
, |

기본적인 키보드 메시지

윈도우즈에서 한글을 고려하지 않고 키보드 입력을 다루는 방법은 정말 쉽다.

Windows는 키보드 입력이 들어올 때 마다 현재 입력 포커스를 가지고 있는 윈도우에게로 아래 메시지를 보내준다.

메시지

내용

WPARAM

LPARAM

WM_CHAR

문자가 조합된 경우

조합된 글자
(TCHAR형으로 넘어옴)

0~15: 반복 횟수
16~23: 스캔 코드
24: 확장 키가 눌렸는가?
29: alt키가 눌려졌는가
30: 이전에 눌려진 상태로 있었는가?
31: 아직 눌려진 상태로 있는가?

WM_KEYDOWN

키보드에서 키가 눌려짐

눌러진 virtual key

동일

WM_KEYUP

키보드에서 키가 눌려졌다 떼어짐

떼어진 virtual key

동일

WM_SYSKEYDOWN

Alt키가 눌려진 상태에서 키가 눌려짐

눌러진 virtual key

동일, 29번 비트는 항상 1

WM_SYSKEYUP

Alt키가 눌려진 상태에서 키가 떼어짐

떼어진 virtual key

동일, 29번 비트는 항상 1

위의 표에서 대부분은 자명한 것이다. 이 중 몇 가지 사항만 짚고 넘어가면 된다.

가장 먼저 이야기 해야 할 것이 WM_CHAR 메세지 이다. 이 메시지는 메인 루프의 TranslateMessage(&msg)에 의해 생겨나는 것이다. 이 함수는 MSG msg 구조체 내의 message, wParam, lParam 멤버와 time멤버를 분석하여 WM_KEYDOWN과 WM_KEYUP으로부터 적당한 갯수의 WM_CHAR를 만들어 낸다. 이 때, 제어판에서 설정한 키 입력 반복 속도 정보가 사용된다.

다음으로 기억해야 할 것은 TCHAR형이다. TCHAR를 알기 전에 WCHAR를 알아야 한다. Win32 API는 유니코드를 지원한다. 2바이트 유니코드 문자 한개를 저장하는 자료형이 WCHAR이다. 다음은 각각 유니코드를 사용하지 않는 소스 코드와(이러한 방식의 한글 표현을 Double Bytes Character Set, DBCS라고 한다) 유니코드를 사용하는 소스 코드를 보여준다.

DBCS 방식

	char a[] = "안녕하세요";
	cout << strlen(a); /* 아마 10이 출력될 것이다 */

유니 코드 방식

	WCHAR w[] = L"안녕하세요";
	cout << wcslen(w); /* 아마 5가 출력될 것이다 */

만일 DBCS 방식으로 작성된 코드를 아시아권 국가에 배포하기 위해 유니코드 방식으로 바꾸려면 어떻게 하면 될까? 혹은 유니코드를 지원하는 소스 코드를 유니코드를 필요로 하지 않는 사용자들을 위해(대신 코드는 가벼워질 것이다) DBCS 방식으로 바꾸려면 어떻게 하면 될까? 아래와 같이 코딩하면 이를 간단히 할 수 있다.

	#define _UNICODE /* 만일 유니코드를 사용하고 싶으면 이 문장을 추가하고 아니면 이 문장을 빼시오 */
	TCHAR w[] = _T("안녕하세요");
	cout << _tcslen(w); 

만일 유니코드를 사용하고 싶지 않으면 #define _UNICODE를 지우면 된다. 이것은 의 구현이다. 내부적으로는 다음과 같이 구현되어 있다.

	#ifdef _UNICODE 
		typedef WCHAR TCHAR;
		#define _T(x) L##x
		#define _tcslen wcslen
	#else
		typedef char TCHAR;
		#define _T(x) x
		#define _tcslen strlen
	#endif

_T(x) 매크로를 정의할 때 ANSI C의 토큰 페이스트 ##가 사용되었다. 이 매크로는 "abc"를 L"abc"로 바꾸어야 하지만(떼어서 쓰면 안되고 반드시 붙여서 써야함), #define _T(x) Lx라고 할 수 도 없지 않은가? ##기호는 L과 x가 서로 다른 기호라는 것을 알려준다.

_T 매크로 대신 __TEXT, _TEXT, TEXT, __T를 사용하여도 동일한 결과를 얻을 수 있으며, 실제로는 _tcslen보다 Windows API 함수인 lstrlen, lstrcmp, lstrcpy 등이 훨씬 많이 사용된다.

정리하면 우리가 _UNICODE를 define 했는가 아닌가에 따라서 윈도우즈는 때때로 char형을, 때때로 WCHAR 형을 WM_CHAR 메세지의 wParam으로 넘겨줄 것이다.

마지막으로 virtual key에 대해 이야기해 보자. 각각의 키보드는 눌려지거나 떼어졌을 때 컴퓨터로 눌려지거나 떼어진 키 번호를 보낸다. 이 키 번호를 'scan code'라고 한다.^^;; 그러나 scan code는 키보드 종류에 따라 다르다. 따라서 윈도우즈는 응용 프로그램 제작자들의 편의를 위해 이 스캔 코드를 virtual key로 바꾸어준다.

이러한 서비스는 아주 편리하다. 분명히 모든 키보드에에서 현재 내 오른쪽 새끼손가락 근처에 있는 엔터키와 Numpad에 있는 엔터키의 스캔 코드는 다르다. 그러나 어느 경우나 WM_KEYDOWN 메시지에는 VK_RETURN으로 들어올 것이다.(그리고 WM_CHAR 메시지에는 '\r' 문자가 들어올 것이다)

키 코드

내용

실제 값

VK_CANCEL

Ctrl+Break를 눌렀을때

03

VK_BACK

Backspace 키

08

VK_TAB

Tab키

09

VK_RETURN

Enter 키

13

VK_SHIFT

Shift키

16

VK_CONTROL

Ctrl 키

17

VK_MENU

Alt 키

18

VK_CAPITAL

Caps Lock 키

20

VK_ESCAPE

Esc 키

27

VK_SPACE

Space 바

32

VK_PRIOR

Page Up 키

33

VK_NEXT

Page Down 키

34

VK_END

End 키

35

VK_HOME

Home 키

36

VK_LEFT

좌측 화살표

37

VK_UP

위쪽 화살표

38

VK_RIGHT

우측 화살표

39

VK_DOWN

아랫쪽 화살표

40

VK_INSERT

Insert키

45

VK_DELETE

Delete키

46

VK_F1 ~ VKF10

F1~F10

112-121

VK_NUMLOCK

Num Lock

144

VK_SCROLL

Scroll Lock

145

Windows에 운영체제의 성능에 대해서 못마땅해 하는 사람들은, 이러한 다대일 대응이 문제를 일으키기를 기대할 수 도 있다. 예를 들어 Numpad의 4, 6, 8, 2는 게임등에서 왼쪽, 오른쪽, 위, 아래를 나타내는데 사용될 수 있지만, 이것이 키보드의 숫자가 눌려졌을 때도 작동한다는 것은 비극적인 일이다. 그러나 설마 그 정도로 어정쩡 하겠는가? 전자의 경우 lParam의 24번째 비트(확장 키가 눌렸는가?)는 1이 되고, 후자의 경우는 0이 된다.

캐럿

캐럿과 관련되어 용어상 분명히 해 두어야 할 것이 있다. 캐럿은 커서가 아니다. 여러분이 워드 프로세서나 메모장 등을 띄웠을 때 여러분의 입력을 기다리는 깜박이는 것이 캐럿이다. 그렇다면 커서는 무엇이란 말인가? 여러분이 책상 위에서 마우스를 움직일 때 모니터 상에서 따라 움직이는 화살표가 바로 커서이다. WNDCLASS를 만들 때 LoadCursor(NULL, IDC_ARROW);를 했던 사실을 잊었는가?

Win32에서 캐럿을 다루는 함수는 다음과 같다.

  • 캐럿을 생성: CreateCaret(HWND hwnd, HBITMAP hBitmap, int width, int height)
  • 캐럿을 보임: ShowCaret(HWND hwnd)
  • 캐럿의 이동: SetCaretPos(int x, int y)
  • 캐럿을 숨김: HideCaret(HWND hwnd)
  • 캐럿을 파괴: DestroyCaret()

응용 프로그램 범위에서 캐럿을 단 한 개만 생성할 수 있음에 주의하라. 오직 하나의 윈도우만이 캐럿을 가져야 한다. 가장 좋은 방법은 WM_SETFOCUS에서 캐럿을 생성하고, WM_KILLFOCUS에서 캐럿을 삭제 하는 것이다. 이 두 메시지는 반드시 쌍으로 불려지므로 메모리상을 둥둥 떠다니는 캐럿을 걱정할 필요는 없다.

또한 HideCaret을 10번 호출했으면, ShowCaret을 10번 호출해야 캐럿을 볼 수 있음을 주의하라. 캐럿은 암기력이 좋은 친구이다.

IME 메시지

한글 Windows를 비롯한 DBCS을 사용하는 국가의 윈도우즈에는 여러개의 키보드 입력이 한 개의 글자를 만드는 일을 관리해 주는 IMM(Input Method Manager)이 내장되어 있다. 키보드에서 문자가 입력되면 IMM이 여러분의 입력을 가로채서 한 글자가 완성되었을 때 비로소 WM_CHAR 메시지를 보내준다.

여러분의 프로그램이 IMM을 무시한채, 단지 WM_CAHR 만을 처리하더라도, 여러분의 프로그램은 대부분의 경우에 잘 작동할 것이다.(잠시후에 왜 잘 작동하는가를 알게 된다)그러나 한 글자가 완성되었을 때 비로소 화면에 나타나는 그런 프로그램이 아니라 한 개의 자모 단위로 입력되고 지워지는 과정을 전부 처리할 수 있는 프로그램을 작성하고 싶다면, IMM이 보내는 IME(Input Method Editor) 메시지들을 핸들링하라.

이 절에서는 IME 메시지들을 알아보고 다음 절에서 한글 타자 연습 프로그램을 만들 것이다. 만일 여러분이 프로그램에서 IMM을 다루고 싶다면, Project 메뉴의 Setting에서 imm32.lib를 링크에 추가하고 소스 코드에는 를 include 해야 한다.

다음은 기본적인 IME 메시지들이다.

메시지

내용

WM_IME_KEYDOWN

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 눌려졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지 DefWndProc에 넘기면 그에 해당하는 WM_KEYDOWN이 불린다.

WM_IME_KEYUP

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 떼어졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지를 DefWndProc에 넘기면 그에 해당하는 WM_KEYUP이 불린다.

WM_IME_CHAR

문자가 조합이 끝났을 때 IMM에의해 보내지는 메시지이다.

만일 _UNICODE가 #define되어 있다면 WM_IME_CHAR는 디폴트 동작으로 한번의 WM_CHAR를 발생시키고 wParam에 WCHAR형의 글자를 넘긴다. 만일 _UNICODE가 #define되어있지 않다면, WM_IME_CHAR는 디폴트 동작으로 두 번의 WM_CHAR를 발생시키고 wParam으로는 상위바이트, 하위바이트를 차례대로 넘긴다.

만일 입력이 들어오면 배열에 문자를 저장하는 코드가 있다면, 이 코드가 한글과같은 Double Bytes Character를 고려하지 않고 작성되었더라도, 한글이 입력되었을 때는 두 번의 WM_CHAR가 차례로 상위바이트, 하위 바이트를 넘기므로, 아무런 문제 없이 작동할 것이다. 많은 외국 회사에서 작성한 에디터나 텔넷 프로그램들이 한글 Windows에서 그렇게 작동하고 있는 것이다.

그러나 위에 소개한 세 개의 IME 메시지보다 더 중요한 메시지들이 있다.

메시지

의미

WM_IME_STARTCOMPOSITION

문자가 조합이 시작

WM_IME_COMPOSITION

문자가 조합 중

WM_IME_ENDCOMPOSITION

문자가 조합이 끝남

WM_IME_STARTCOMPOSITION과 WM_IME_ENDCOMPOSITION 메시지는 한글 조합이 시작할 때와 끝났을 때 알려주는 메시지이며, 필요하지 않으면 대게의 경우 DefWndProc로 넘겨진다. 그러나 WM_IME_COMPOSITION 메세지는 한글모드에서 한글이 조합되는 중 발생하므로 만일 완전한 조합이 되지 않은 글자의 출력을 원한다면 반드시 처리해야 한다.

WM_IME_COMPOSITION이 발생하면 lParam의 값을 검사해서 현재 글자가 확정되었는지 확정되지 않았는지 알수 있다. 이 때 wParam으로는 새로 추가된 글자가 넘어오지만 대부분의 경우 ImmGetCompositionString 함수를 호출하여 현재까지의 변경된 버퍼 상태를 얻어오는 것이 일반적이다. 다음은 키보드 입력에 따른 Composition 버퍼의 내용이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
3 GCS_RESULTSTR 다3

다음은 사용자가 backspace를 눌러 조합중인 음소를 지우는 경우이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
Back Space GCS_COMPSTR
Back Space GCS_COMPSTR NULL (길이 0)

위의 표를 잘 분석해 보면, 우리는 lParam에 GCS_COMPSTR이 들어올 때는 캐럿 위치를 증가시키지 않고 단지 Composition 버퍼의 내용을 현재 캐럿 위치에 출력하고, lParam에 GCS_RESULTSTR이 들어오면 이 때는 WM_CHAR 또한 불릴 것이므로 WM_CHAR에서 글자를 출력하고 캐럿 위치를 이동하여야 함을 알 수 있다.

마지막으로 IMM의 상태가 변경되었을 때 우리에게 알려주는 메시지를 알아보고 이 절을 마치도록 하자.

메시지

내용

wParam

WM_IME_NOTIFY

IMM의 상태가 바뀔 때

글자 입력창 관련

IMN_OPENCANDIDATE
IMN_CHANGECANDIDATE
IMN_SETCANDIDATEPOS
IMN_CLOSECANDIDATE

상태 창 관련

IMN_OPENSTATUSWINDOW
IMN_SETOPENSTATUS
IMN_SETSTATUSWINDOWPOS
IMN_CLOSE_STATUSWINDOW

문자 조합 관련

IMN_SETCOMPOSITIONFONT
IMN_SETCOMPOSITIONWINDOW

모드 관련

IMN_SETCONVERSIONMODE
IMN_SETSENTENCEMODE

예를 들어 한/영 상태가 변경될 때 마다 상태바에 한/영 상태를 표시해 주고 싶다면 WM_IME_NOTIFY에서 wParam이 IMN_SETCONVERSIONMODE가 들어올 때 현재 IME 상태를 얻어 상태바에 표시해 주면 된다. 다음은 현재 IME 상태를 얻어오는 코드이다.

	DWORD dwConversion, dwSentence; /* 현재의 IME 상태가 저장될 곳이다 */
	HIMC himc = ImmGetContext(hwnd); /* 현재 input context의 핸들을 얻어 온다 */
	ImmGetConversionStatus(himc, &dwConversion, &dwSentence); /* 현재 IME 상태를 얻어 온다. */
	ImmReleaseContext(hwnd, himc); /* input context의 핸들을 반납한다 */

출처 : http://cafe.naver.com/cyberzone.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=400
반응형

'Programming > Win32API' 카테고리의 다른 글

윈도우 투명  (0) 2011.10.30
한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
Posted by blueasa
, |

출처 : GPG스터디 http://www.gpgstudy.com/forum/viewtopic.php?t=8137&highlight=ime+%C7%D1%B1%DB

 

윈도우 메시지 프로시저로 IME의 컨버전 모드가 변경 되었을 경우 아래와 같이 메시지가 옵니다.

코드:
  if (WM_IME_NOTIFY == Message)
  {
    switch (wParam)
    {
    case IMN_SETCONVERSIONMODE:
      {
        //한영키가 눌렸는가 검사
        HIMC hIMC = NULL;  

        if (hIMC = ImmGetContext(this->GetWindowHandle()))  
        {  
          DWORD fdwConversion, fdwSentence;  

          BOOL bRet = ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);  

          if(bRet) 
          {  
            bRet = (fdwConversion & IME_CMODE_NATIVE ? TRUE : FALSE);  

            if (bRet)
            {
              //한글 모드임!
            }
            else
            {
              //영문 모드임!
            }
          }

          ImmReleaseContext(this->GetWindowHandle(), hIMC);
        }  

      }
    
    }


이렇게 알아 낸 후 컨버전 모드를 변경하고 싶다면 아래와 같이 하면 됩니다

코드:
//영문으로 변경하고 싶다면..
DWORD dwMode = IME_CMODE_ALPHANUMERIC;

//한글로 변경하고 싶다면..
DWORD dwMode = IME_CMODE_NATIVE;

ImmSetConversionStatus(hImc, dwMode, NULL);


대략 무조건 영문으로 고정을 시키시고 싶으신듯 하니.. 아래와 같이 간편화가 될듯 합니다.

코드:
if (WM_IME_NOTIFY == Message)
  {
    switch (wParam)
    {
    case IMN_SETCONVERSIONMODE:
      {
        //한영키가 눌렸는가 검사
        HIMC hIMC = NULL;  

        if (hIMC = ImmGetContext(this->GetWindowHandle()))  
        {  
           ImmSetConversionStatus(hImc, IME_CMODE_ALPHANUMERIC, NULL);
        }

          ImmReleaseContext(this->GetWindowHandle(), hIMC);
        }  

      }
    
    }
반응형

'Programming > Win32API' 카테고리의 다른 글

한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
Keyboard 입력 받기  (0) 2010.09.03
IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Posted by blueasa
, |

IME

Programming/Win32API / 2010. 9. 2. 17:07

먼저 IME를 사용하려면 프로젝트에 Imm32.lib를 추가하고, imm.h를 인클루드 해야한다.



IME 메시지

WM_IME_STARTCOMPOSITION 
    IME가 조립 문자열을 만들기 직전에 보냄. WPARAM, LPARAM의 값은 없음. 이 메시지를 DefWindowProc으로
    보내지 않으면 조립윈도우가 나타나지 않는다.

WM_IME_ENDCOMPOSITION
    조립이 끝났다는 통지 메시지. 인수와 리턴값 없음. 커스텀 IME 윈도우를 작성하지 않는다면 무시해도 무방함.

WM_IME_COMPOSITION
    조립 상태가 변경될때마다 보내진다. 
    WPARAM - 조립중의 문자의 코드가 전달, 이 코드는 2byte의 DBCS문자로 조립중인 중간 문자코드이다.
    LPARAM - 조립상태가 어떻게 변경되었는지, 이 문자를 어떻게 처리해야 하는지를 나타내는 플래그의 집합.
                    한글의 경우 다음 두 플래그가 특히 중요함.
                        GCS_COMPSTR : 아직 문자를 조립중이라는 뜻, 즉 아직 한 음절이 완성되지는 않았음.
                        GCS_RESULTSTR : 한 음절을 완전히 조립했다는 뜻.
                    이 플래그들이 있는지 살펴보면 문자가 완성된 것인지, 조립중인지 알 수 있음.

WM_IME_CHAR
    문자 하나가 완성되었을때 보내짐.
    WPARAM - 완성된 문자의 코드가 전달. 1byte만 전달되는 WM_CHAR과는 달리 DBCS일 수 있음.
                     (단, 유니코드 윈도우에서는 WM_CHAR, WM_IME_CHAR 모두 2byte이다.)
    이 메시지를 무시하면 한글 한 문자에 대해 WM_CHAR 메시지를 두번 받게 된다.

WM_IME_SETCONTEXT
    응용프로그램이 활성/비활성화될 때 보내진다. WPARAM이 TRUE이면 활성, FALSE이면 비활성화 되었다는 뜻이다.

WM_IME_NOTIFY
    IME 윈도우가 변경되었다는 통지 메시지이다. WPARAM으로 어떤 변경인지 통보됨.한글 입력, 영문 입력모드를
    변경할 때도 이 메시지가 전달된다.



Input Context 생성, 해제

Input Context(입력 컨텍스트) : IME가 내부적으로 사용하는 구조체이며 조립 문자열, 변환모드, IME 윈도우의 위치 등 IME의 현재 상태에 대한 정보들이 저장됨.


Input Context의 핸들을 얻는 함수

HIMC ImmGetContext(void); 
BOOL ImmReleaseContext(HWND hWnd, HIMC hIMC); 

Input Context를 조작하는 함수

BOOL ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence); 
BOOL ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence); 

    입력모드를 한글로 변환하고 싶으면
ImmSetConversionStatus(hImc, IME_CMODE_NATIVE, IME_SMODE_NONE); 

    입력모드를 영어로 변환하고 싶으면
ImmSetConversionStatus(hImc, 0, IME_SMODE_NONE); 
를 호출하면 된다.

    하지만 시스템이 만드는 Default Input Context는 스레드 내의 모든 윈도우가 공유하기 때문에 한글이나 영문으로 변경시
    모든 입력모드가 통일되게 변경된다. 만약 각각의 컨트롤에서 다른 입력모드를 주고 싶다면 윈도우별로 InputContext를
    생성, 해제하여 연결시키면 된다.


Input Context를 생성, 해제하는 함수

// InputContext를 위한 메모리를 할당하고, 그 핸들을 리턴 HIMC ImmCreateContext(void); 
// 특정 윈도우와 연결 HIMC ImmAssociateContext(HWND hWnd, HIMC hIMC); 
// InputContext를 메모리에서 해제 BOOL ImmDestroyContext(HIMC hIMC); 

    InputContext를 생성, 해제할 경우에는 Pen, Brush를 생성, 해제할때와 같은 방법으로 한다.
 
 
 
 
 
 
 
 
 
---
 
 
IME 활성, 비활성 제어 ( 출처 : http://smilewjp.springnote.com/pages/3182684 )
 

IME 관련 작업을 하다보면 IME의 활성/비활성 상태를 강제로 조정해야할 필요가 생깁니다.

관련 자료를 찾기 위해 인터넷을 검색하다보니 비밀번호나 아이디로 영문만 입력받고자 할때 많이 사용하더군요.

 

저같은 경우에는 중국어 관련해서 사설 IME를 사용하는데 문제가 생겨서 사용했습니다.

사설IME에서 입력을 받으면 안되는 상황에서 입력을 받고있어서 문제가 발생했습니다.

그래서 IME를 비활성 시키는 구문을 찾아서 넣었습니다.

  1. HIMC ImmAssociateContext( HWND hWnd, HIMC hImc );

MSDN의 ImmAssociateContext()를 살펴보면 이 API는 윈도우 별로 입력 컨텍스트를 만들었을때 컨텍스트를

지정하는데 사용할 수 있지만 hImc의 값에 NULL을 줄 경우, 해당 윈도우 창의 IME 포커스를 죽이게 됩니다.

따라서 관련된 IME는 동작하지 않게 되고, 사설 IME역시 동작을 하지 않습니다.

 

하지만 중요하게 알고 있어야 하는것은 ImmAssociateContext()를 할 경우 리턴값으로 기존의 HIMC값이 반환되기 때문에

나중에 사용을 위해서는 저장해 두어야합니다.

  1. void SetActive( BOOL isActive )
    {
       if( isActive )
       {
          // 기존의 값으로 IME를 다시 설정합니다.
          ImmAsscociateContext( hWnd, _oldhImc );
       }
       else
       {
          _oldhImc = ImmAssociateContext( hWnd, NULL );
          // IME를 비활성 시킵니다.
          // _oldhImc는 값을 저장하고 있어야 합니다.
       }
    }

출처 : Tong - race0203님의 C++통

반응형

'Programming > Win32API' 카테고리의 다른 글

Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
Posted by blueasa
, |

getWindowRect 은 윈도우 전체 화면에 대한 좌표를 말하며

getClientRect 는 각 핸들에 대한 좌표를 말한다.

 

getWindowRect 사용시

 

cRect.left  화면 좌측에서 핸들 좌측까지의 거리

cRect.right 화면 좌측에서 핸들 우측까지의 거리

cRect.top  화면 위쪽에서 핸들 위쪽까지의 거리

cRect.bottom 화면 위쪽에서 핸들 아래쪽까지의 거리

 

즉. 기준은 화면의 좌측과 위쪽이며, 그 기준에서 핸들의 각 위치까지의 거리를 말한다.

따라서 핸들의 가로 길이는 right - left, 세로 길이는 bottom - top 하면 구할 수 있다.

 

getClientRect 사용시

 

cRect.left  핸들 좌측에서 핸들 좌측까지의 거리

cRect.right 핸들 좌측에서 핸들 우측까지의 거리

cRect.top  핸들 위쪽에서 핸들 위쪽까지의 거리

cRect.bottom 핸들 위쪽에서 핸들 아래쪽까지의 거리

 

기본 개념은 getWindowRect와 같다. 다만 기준 위치가 다를 뿐이다.

기준위치가 핸들의 좌측과 위쪽이므로

cRect.left 와 cRect.top은 항상 0이 된다.

cRect.right 는 핸들의 가로 길이 cRect.bottom은 핸들의 세로 길이가 된다.


출처 : http://maximaro.blog.me/50047243920

반응형

'Programming > Win32API' 카테고리의 다른 글

IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
Drag & Drop 예제 소스  (0) 2010.04.20
Posted by blueasa
, |

MFC 에서는 AfxGetInstanceHandle() 로 쉽게 구할 수 있다.

Win32 API 에서는 (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE) 로 얻을 수 있다.

여기서 Win32 API 의 경우에는 윈도우 핸들 hWnd 가 필요하다.

Win32 API 에도 윈도우 핸들 없이 HINSTANCE 를 구하는 함수가 있다.

GetModuleHandle(NULL) 을 호출하면 HINSTANCE 를 반환한다.


반응형

'Programming > Win32API' 카테고리의 다른 글

IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
Virtual Keys, Standard Set  (0) 2010.04.21
Drag & Drop 예제 소스  (0) 2010.04.20
윈도우 핸들 제어  (0) 2010.04.14
Posted by blueasa
, |

VC깔린곳에 include폴더를 보시면 winuser.h파일이 있는데요.

 

파일내용중에 해당 부분을 찾으실수 있을겁니다.

참고하시라고 제가 가진 파일의 일부를 적습니다.


/*
 * Virtual Keys, Standard Set
 */
#define VK_LBUTTON        0x01
#define VK_RBUTTON        0x02
#define VK_CANCEL         0x03
#define VK_MBUTTON        0x04    /* NOT contiguous with L & RBUTTON */

#define VK_BACK           0x08
#define VK_TAB            0x09

#define VK_CLEAR          0x0C
#define VK_RETURN         0x0D

#define VK_SHIFT          0x10
#define VK_CONTROL        0x11
#define VK_MENU           0x12
#define VK_PAUSE          0x13
#define VK_CAPITAL        0x14

#define VK_KANA           0x15
#define VK_HANGEUL        0x15  /* old name - should be here for compatibility */
#define VK_HANGUL         0x15
#define VK_JUNJA          0x17
#define VK_FINAL          0x18
#define VK_HANJA          0x19
#define VK_KANJI          0x19

#define VK_ESCAPE         0x1B

#define VK_CONVERT        0x1C
#define VK_NONCONVERT     0x1D
#define VK_ACCEPT         0x1E
#define VK_MODECHANGE     0x1F

#define VK_SPACE          0x20
#define VK_PRIOR          0x21
#define VK_NEXT           0x22
#define VK_END            0x23
#define VK_HOME           0x24
#define VK_LEFT           0x25
#define VK_UP             0x26
#define VK_RIGHT          0x27
#define VK_DOWN           0x28
#define VK_SELECT         0x29
#define VK_PRINT          0x2A
#define VK_EXECUTE        0x2B
#define VK_SNAPSHOT       0x2C
#define VK_INSERT         0x2D
#define VK_DELETE         0x2E
#define VK_HELP           0x2F

/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */

#define VK_LWIN           0x5B
#define VK_RWIN           0x5C
#define VK_APPS           0x5D

#define VK_NUMPAD0        0x60
#define VK_NUMPAD1        0x61
#define VK_NUMPAD2        0x62
#define VK_NUMPAD3        0x63
#define VK_NUMPAD4        0x64
#define VK_NUMPAD5        0x65
#define VK_NUMPAD6        0x66
#define VK_NUMPAD7        0x67
#define VK_NUMPAD8        0x68
#define VK_NUMPAD9        0x69
#define VK_MULTIPLY       0x6A
#define VK_ADD            0x6B
#define VK_SEPARATOR      0x6C
#define VK_SUBTRACT       0x6D
#define VK_DECIMAL        0x6E
#define VK_DIVIDE         0x6F
#define VK_F1             0x70
#define VK_F2             0x71
#define VK_F3             0x72
#define VK_F4             0x73
#define VK_F5             0x74
#define VK_F6             0x75
#define VK_F7             0x76
#define VK_F8             0x77
#define VK_F9             0x78
#define VK_F10            0x79
#define VK_F11            0x7A
#define VK_F12            0x7B
#define VK_F13            0x7C
#define VK_F14            0x7D
#define VK_F15            0x7E
#define VK_F16            0x7F
#define VK_F17            0x80
#define VK_F18            0x81
#define VK_F19            0x82
#define VK_F20            0x83
#define VK_F21            0x84
#define VK_F22            0x85
#define VK_F23            0x86
#define VK_F24            0x87

#define VK_NUMLOCK        0x90
#define VK_SCROLL         0x91

/*
 * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
 * Used only as parameters to GetAsyncKeyState() and GetKeyState().
 * No other API or message will distinguish left and right keys in this way.
 */
#define VK_LSHIFT         0xA0
#define VK_RSHIFT         0xA1
#define VK_LCONTROL       0xA2
#define VK_RCONTROL       0xA3
#define VK_LMENU          0xA4
#define VK_RMENU          0xA5

#if(WINVER >= 0x0400)
#define VK_PROCESSKEY     0xE5
#endif /* WINVER >= 0x0400 */

#define VK_ATTN           0xF6
#define VK_CRSEL          0xF7
#define VK_EXSEL          0xF8
#define VK_EREOF          0xF9
#define VK_PLAY           0xFA
#define VK_ZOOM           0xFB
#define VK_NONAME         0xFC
#define VK_PA1            0xFD
#define VK_OEM_CLEAR      0xFE

#define VK_A     0x41
#define VK_B     0x42
#define VK_C     0x43
#define VK_D     0x44
#define VK_E     0x45
#define VK_F     0x46
#define VK_G     0x47
#define VK_H     0x48
#define VK_I     0x49
#define VK_J     0x4A
#define VK_K     0x4B
#define VK_L     0x4C
#define VK_M     0x4D
#define VK_N     0x4E
#define VK_O     0x4F
#define VK_P     0x50
#define VK_Q     0x51
#define VK_R     0x52
#define VK_S     0x53
#define VK_T     0x54
#define VK_U     0x55
#define VK_V     0x56
#define VK_W     0x57
#define VK_X     0x58
#define VK_Y     0x59
#define VK_Z     0x5A

 

가상키이름  bVK헥사값 bVK 파라메터  
VK_LBUTTON 1 1 마우스 왼쪽 버튼
VK_RBUTTON 2 2 마우스 오른쪽 버튼
VK_CANCEL 3 3 Ctrl + C
VK_MBUTTON 4 4 마우스 가운데 버튼
VK_BACK 8 8 Backspace
VK_TAB 9 9 Tab
VK_CLEAR 0C 12 CLEAR
VK_RETURN 0D 13 Enter
VK_SHIFT 10 16 Shift
VK_CONTROL 11 17 Ctrl(좌측)
VK_MENU 12 18 Alt(좌측)
VK_PAUSE 13 19 Pause Break
VK_CAPITAL 14 20 Caps Lock
VK_HANGUL 15 21 한/영 키
VK_HANJA 19 25 한자 키
VK_ESCAPE 1B 27 ESC
VK_SPACE 20 32 Spacebar
VK_PRIOR 21 33 Page Up
VK_NEXT 22 34 Page Down
VK_END 23 35 End
VK_HOME 24 36 Home
VK_LEFT 25 37 Left Arrow(←)
VK_UP 26 38 Up Arrow(↑)
VK_RIGHT 27 39 Right Arrow(→)
VK_DOWN 28 40 Down Arrow(↓)
VK_SELECT 29 41 Select
VK_EXECUTE 2B 43 EXECUTE
VK_SNAPSHOT 2C 44 PrtScr
VK_INSERT 2D 45 Insert
VK_DELETE 2E 46 Delete
VK_HELP 2F 47 Help
VK_0 30 48 0 키
VK_1 31 49 1 키
VK_2 32 50 2 키
VK_3 33 51 3 키
VK_4 34 52 4 키
VK_5 35 53 5 키
VK_6 36 54 6 키
VK_7 37 55 7 키
VK_8 38 56 8 키
VK_9 39 57 9 키
VK_A 41 65 A 키
VK_B 42 66 B 키
VK_C 43 67 C 키
VK_D 44 68 D 키
VK_E 45 69 E 키
VK_F 46 70 F 키
VK_G 47 71 G 키
VK_H 48 72 H 키
VK_I 49 73 I 키
VK_J 4A 74 J 키
VK_K 4B 75 K 키
VK_L 4C 76 L 키
VK_M 4D 77 M 키
VK_N 4E 78 N 키
VK_O 4F 79 O 키
VK_P 50 80 P 키
VK_Q 51 81 Q 키
VK_R 52 82 R
VK_S 53 83 S 키
VK_T 54 84 T 키
VK_U 55 85 U 키
VK_V 56 86 V 키
VK_W 57 87 W 키
VK_X 58 88 X 키
VK_Y 59 89 Y 키
VK_Z 5A 90 Z 키
VK_LWIN 5B 91 윈도우키(좌측)
VK_RWIN 5C 92 윈도우키(우측)
VK_APPS 5D 93 App Menu 키
VK_NUMPAD0 60 96 숫자키패드 0
VK_NUMPAD1 61 97 숫자키패드 1
VK_NUMPAD2 62 98 숫자키패드 2
VK_NUMPAD3 63 99 숫자키패드 3
VK_NUMPAD4 64 100 숫자키패드 4
VK_NUMPAD5 65 101 숫자키패드 5
VK_NUMPAD6 66 102 숫자키패드 6
VK_NUMPAD7 67 103 숫자키패드 7
VK_NUMPAD8 68 104 숫자키패드 8
VK_NUMPAD9 69 105 숫자키패드 9
VK_MULTIPLY 6A 106 숫자키패드 *
VK_NUMADD 6B 107 숫자키패드 +
VK_SEPARATOR 6C 108  SEPARATOR
VK_SUBTRACT 6D 109 숫자키패드 -
VK_DECIMAL 6E 110 숫자키패드 .
VK_DEVIDE 6F 111 숫자키패드 /
VK_F1 70 112 F1 키
VK_F2 71 113 F2 키
VK_F3 72 114 F3 키
VK_F4 73 115 F4 키
VK_F5 74 116 F5 키
VK_F6 75 117 F6 키
VK_F7 76 118 F7 키
VK_F8 77 119 F8 키
VK_F9 78 120 F9 키
VK_F10 79 121 F10 키
VK_F11 7A 122 F11 키
VK_F12 7B 123 F12 키
VK_F13 7C 124 F13 키
VK_F14 7D 125 F14 키
VK_F15 7E 126 F15 키
VK_F16 7F 127 F16 키
VK_F17 80 128 F17 키
VK_F18 81 129 F18 키
VK_F19 82 130 F19 키
VK_F20 83 131 F20 키
VK_F21 84 132 F21 키
VK_F22 85 133 F22 키
VK_F23 86 134 F23 키
VK_F24 87 135 F24 키
VK_NUMLOCK 90 144 Num Lock 키
VK_SCROLL 91 145 Scroll Lock 키

 

반응형

'Programming > Win32API' 카테고리의 다른 글

IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Drag & Drop 예제 소스  (0) 2010.04.20
윈도우 핸들 제어  (0) 2010.04.14
Posted by blueasa
, |
반응형

'Programming > Win32API' 카테고리의 다른 글

IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
윈도우 핸들 제어  (0) 2010.04.14
Posted by blueasa
, |