블로그 이미지
랜달프

calendar

1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Notice

    2008. 12. 10. 15:47 Programming/VC++(API,MFC,WTL,ATL)


    'Page Up'이나 'Page Down'등을 눌렀을 때 응용 프로그램이 반응하려면 WM_KEYDOWN이나 WM_KEYUP 메시지를 처리한다.

     

    인쇄 가능한 문자를 나타내는 키를 눌렀을 때는 (키누름이나 키해제 메시지를 무시하고) 키보드에서 입력된 문자를 나타내는 WM_CHAR 메시지를 처리하면 된다.

     

    WM_KEYUP/DOWN 메시지 대신 WM_CHAR메시지를 사용하면 이벤트와 키 누름 주위의 상황(Shift가 눌러져 있는지 Caps Lock이 켜져 있는지)등에 대한 요인들을 Windows가 처리해주므로 쉽게 문자를 처리할 수 있다.

     

     

    입력포커스

     

    키보드로 부터 입력을 받는 창은 포커스를 갖고 있는 창이다.

    Windows는 WM_SETFOCUS와 WM_KILLFOCUS 메시지를 통해 입력 포커스를 받거나 잃은 것에 대한 정보를 창에 알린다.

     

    void CWnd::OnSetFocus(CWnd* pOldWnd)    // pOldWnd는 포커스를 잃은 창

    void CWnd::OnKillFocus(CWnd* pNewWnd)   // pNewWnd는 포커스를 얻은 창

     

    CWnd::SetFocus() 를 사용하면 입력 포커스를 다른 창으로 옮길 수 있다.

     

    CWnd* pFocusWnd = CWnd::GetFocus() 를 사용하면 현재 누가 입력포커스를 갖고 있는지 알 수 있다.(다른 응용프로그램의 창 포인터는 얻을 수 없다. NULL이 리턴된다.)

     

     

    키입력 메시지

     

    키가 눌려지면 입력포커스가 있는 창에 가상 키코드와 함께 WM_KEYDOWN 메시지가 전달된다.

    그리고, 키가 해제되면 WM_KEYUP 메시지가 전달된다.

     

    'Alt'와 'F10'키를 제외한 모든 키는 WM_KEYDOWN/WM_KEYUP 메시지를 발생시킨다.

    Alt 키를 누르면 WM_KEYDOWN/WM_KEYUP이 아니라 WM_SYSKEYDOWN/WM_SYSKEYUP 메시지가 발생한다.

    F10 키를 누르면 메뉴 바로가기 처리 상태로 변환된다.

     

    WM_KEYDOWN/WM_KEYUP, WM_SYSKEYDOWN/WM_SYSKEYUP은 각각 OnKeyDown/OnKeyUp, OnSysKeyDown/ONKeyUp 메시지 핸들러 함수와 연결된다.

     

    위의 키입력 메시지 핸들러 함수의 원형은 다음과 같다.

    afx_msg void OnMsgName( UINT nChar, UINT nRepCnt, UINT nFlags )

     

      nChar : 누르거나 뗀 키의 가상 키 코드

      nRepCnt : 키 누름 반복 횟수, 한 키를 계속 누르고 있는 경우, 한 메시지로 처리하기 위해..

      nFlags : 키의 스캔코드와 아래표에 정리한 비트 플래그의 조합

     

         0~7 : OEM 스켄코드 - 8비트 OEM 스캔코드

         8 : 확장 키 플래그 - 확장키는 1, 아니면 0

         9~10 : 예약됨 - N/A

         13 : 컨텍스트 코드 - Alt 키가 눌러져 있으면 1, 아니면 0

         14 : 이전 키의 상태 - 바로전에 키를 눌렀으면 1, 아니면 0

         15 : 변화 상태 - 키가 눌려 있으면 0, 아니면 1

     

    ** 컨텍스트코드는 메시지가 생성될 때 Alt 키가 눌려졌는지를 나타낸다.

     

    일반적으로 WM_SYSKEYDOWN/WM_SYSKEYUP은 Windows가 처리하도록 한다.(::DefWindowProc)

     

     

    가상 키 코드

     

    Windows는 가상키코드를 통해 키를 식별하므로 프로그래머는 키보드마다 달라지는 하드코드값이나 OEM스캔코드값을 신경쓸 필요가 없다.

     

    가상 키 코드는 Winuser.h에 정의되어 있다.

     

    문자처리는 위의 키입력 메시지 핸들러에서 가상 키를 처리하는 것보다 WM_CHAR 메시지로 처리하는게 더 좋다.

     

    ** 가상키를 제공하지 않는.. 문자도 숫자도 아닌 키도 있고.. 이러한 키는 국가별로 다르기도 하고.. 등등..

     

     

    Shift 키 상태와 토글

     

    WM_KEYDOWN/WM_KEYUP, WM_SYSKEYDOWN/WM_SYSKEYUP 메시지를 처리할 때 Shift, Ctrl, Alt 의 상태를 확인해야 할 필요가 있을 것이다.

    이때는 ::GetKeyState 함수를 이용한다. 이 함수는 원하는 키가 눌려져 있는지 보고한다.

     

    ::GetKeyState(VK_SHIFT)          // Shift 키가 눌려져 있으면 음수값을 리턴.

    ::GetKeyState(VK_CONTROL)    // Ctrl 키가 눌려져 있으면 음수값을 리턴.

    ..

     

    // Ctrl + 왼쪽 화살표 일때만 ...

    if ((nChar == VK_LEFT) && (::GetKeyState(VK_CONTROL) < 0))  {

       ...

    }

     

    ** GetKeyState에서 Alt를 체크할 필요는 없을 것이다. Alt 키는 누르면 WM_KEYDOWN/UP 이 아니라 WM_SYSKEYDOWN/UP 메시지가 발생하니 해당 핸들러함수에서 처리하면 된다.

     

    ** VK_LBUTTON, VK_MBUTTON, VK_RBUTTON 식별자와 GetKeyState 함수를 결합하면 마우스 단추가 눌려 잇는지 알 수 있다.

     

    ** GetKeyState는 다음과 같이 Num Lock, Caps Lock, Scroll Lock 가 켜져 있는지 꺼져 있는지 확인할 수 있다.

      ::GetKeyState( VK_NUMLOCK ) & 0x01    // 켜져 있으면 0

     

    ::GetKeyState 는 키보드 메시지 핸들러에서만 사용해야 한다.

    키보드 메시지 핸들러 외부에서 키나 마우스단추를 확인하려면 ::GetAsyncKeyState 를 사용한다.

     

     

    문자 메시지

     

    WM_KEYDOWN/UP등과 같은 키보드 메시지 핸들러 텍스트 편집기와 같은 응용 프로그램을 만든다면 어떻게 작업해야 할까...

    프로그래머는 직접 가상 키코드값과 Shift, Caps Lock, Ctrl 등의 키 조합을 다 다루어야 할 것이다.

     

    그러나 Windows는 ::TranslateMessage API 함수를 통해서 문자키를 갖는 키 입력 메시지를 WM_CHAR 메시지로 변환해준다.

    따라서 문자가 들어가는 키입력은 WM_CHAR 메시지 핸들러에서 처리하면 된다.

     

    ** Alt가 눌려진 상태에서 문자가 들어간 키입력은 WM_SYSCHAR 메시지 핸들러로 처리한다.

    ** Alt 조합은 일반적으로 특별한 목적에 사용되기 때문에 대부분 WM_SYSCHAR는 무시한다.

     

    afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )

     

      nChar : ANSI나 Unicode 문자 코드가 저장된다.

      nRepCnt, nFlags 는 키 입력 메시지와 동일하다.

     

     

    데드 키 메시지

     

    언급되지 않은 키보드 메시지가 2개 있다. 이 메시지는 거의 사용되지 않는다.

     

    데드 키는 발음 부호를 나타낸다. 즉, 데드 키를 입력한 다음 문자를 입력하면 액센트 기호가 붙은 문자를 표현할 수 있다.

     

    ::TranslateMessage 는 데드키에 해당하는 WM_KEYUP를 WM_DEARCHAR로 변환하고 데드 키에 해당하는 WM_SYSKEYUP을 WM_SYSDEADCHAR 메시지로 변환한다.

     

     

    캐럿

     

    CWnd는 다음과 같이 7개의 캐럿 함수를 제공한다. 그리고 제공되지는 않지만 ::DestroyCaret 함수도 반드시 필요한 함수이다.

     

    CreateCaret - 비트맵을 이용하여 캐럿을 만든다.

    CreateSolidCaret - 실선 캐럿이나 블록 캐럿을 만든다.

    CreateGrayCaret - 회색 선 캐럿이나 블록 캐럿을 만든다.

    GetCaretPos - 캐럿의 위치를 얻는다.

    SetCaretPos - 캐럿의 위치를 설정한다.

    ShowCaret - 캐럿을 표시한다.

    HideCaret - 캐럿을 감춘다.

     

    ** ::DestroyCaret 생성된 캐럿을 파괴한다.

     

    캐럿은 동일한 스레드에서 실행되는 모든 창에 의해 공유되는 스레드 단위 자원이다.

     

    캐럿을 사용하는 규칙은 다음과 같다.

     

      1. 입력 포커스를 받을 때 캐럿을 만들어야 하고 입력 포커스를 잃을 때는 삭제해야 한다.

     

      2. 캐럿이 만들어져 있다해도 ShowCaret를 해야 표시된다. HideCaret를 하면 숨길 수 있다.

        HIdeCaret를 두번연속 했다면 ShowCaret도 두번해야 캐럿을 다시 볼 수 있다.

     

      3. OnPaint 외부에서 캐럿을 포함하고 있는 창 영역을 그릴 때는 캐럿을 숨겨야 한다.

        (안그러면 화면이 깨진다.)

        OnPaint 안에서 캐럿을 숨기거나 다시 표시할 필요는 없다.

        ::BeginPain와 ::EndPaint가 알아서 해준다.

     

      4. SetFocusPos로 캐럿을 이동시킬 수 있다.

        즉, 윈도우가 자동으로 이동시켜주지 않는다. 프로그래머가 알아서 해야 한다.

     

     

    캐럿의 폭을 찾 테두리의 폭에 맞추는 경우도 있다.

    SM_CXBORDER 값과 함께 ::GetSystemMetrics를 호출하면 창 테두리의 폭을 알 수 있다.

     

    고정폭 글꼴에서는 캐럿의 폭과 높이를 글자 하나의 크기와 같도록 할 수도 있다.

     

    캐럿이동은 CWnd::SetCaretPos로 한다.

     

    고정폭 글꼴은 문자의 위치에 한 문자의 폭을 곱하면 새로운 문자의 위치를 알 수 있다.

     

    가변폭 글꼴은 CDC::GetTextExtent나 CDC::GetTabbedTextExtent 함수를 이용하여 논리적 단위로 가변폭 글꼴의 문자열 폭을 계산할 수 있다.

     

    ** CWnd나 CWnd를 상속받은 창에서 캐럿을 사용하려면 대단히 귀찮은 작업들을 많이 해줘야 한다.   따라서 웬만하면 CEdit와 같은 컨트롤로 해결하도록 한다.

    그러나... CEdit와 같은 클래스로 할 수 없는 다양한 에디팅처리가 꼭 필요하다면 할수 없이 캐럿을 사용해야 한다.

    첨부된 파일은 CWnd를 상속받은 창에서 캐럿을 처리하는 정석을 보여준다.


     

    posted by 랜달프