Overview Mouse, Keyboard Message Mouse Message Keyboard Message HCI Programming 2 (321190) 2008년가을학기 10/15/2008 박경신 2 마우스기초 마우스처리 윈도우운영체제는마우스와관련된모든변화를형태로프로그램에게전달한다. 마우스기초 마우스전달 마우스는마우스커서밑에있는윈도우가받는다. 마우스 마우스를프레임윈도우로전달 마우스를뷰로전달 마우스장치드라이버 시스템대기열 응용프로그램대기열 루프 핸들러 3 4
클라이언트영역마우스 클라이언트영역마우스 클라이언트영역마우스 발생과정예 WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK WM_MOUSEMOVE 발생시점왼쪽버튼을누를때 왼쪽버튼을뗄때 왼쪽버튼을더블클릭할때 가운데버튼을누를때 가운데버튼을뗄때가운데버튼을더블클릭할때 오른쪽버튼을누를때 오른쪽버튼을뗄때오른쪽버튼을더블클릭할때마우스를움직일때 이벤트생성왼쪽마우스를움직일때 왼쪽마우스버튼을클릭했을때 왼쪽마우스버튼을클릭하고드래그 (drag) 했을때 왼쪽마우스버튼을더블클릭했을때 발생과정 WM_MOUSEMOVE -> -> WM_MOUSEMOVE WM_LBUTTONDOWN -> WM_BUTTONUP WM_LBUTTONDOWN -> WM_MOUSEMOVE -> -> WM_LBUTTONUP WM_LBUTTONDOWN -> WM_LBUTTONUP -> WM_LBUTTONDBCLK -> WM_LBUTTONUP 5 6 클라이언트영역마우스 클라이언트영역마우스핸들러 클라이언트영역마우스 핸들러형태 맵매크로 핸들러 afx_msg void On* (UINT nflags, CPoint point) ; WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK WM_MBUTTONDOWN WM_MBUTTONUP ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_LBUTTONDBLCLK() ON_WM_MBUTTONDOWN() ON_WM_MBUTTONUP() OnLButtonDown OnLButtonUp OnLButtonDblClk OnMButtonDown OnMButtonUp nflags 가생성될때의키보드나마우스버튼의상태를나타내는비트매스크 point 가생성될때의마우스커서위치 ( 클라이언트좌표 ) WM_MBUTTONDBLCL WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK WM_MOUSEMOVE ON_WM_MBUTTONDBLCLK() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_RBUTTONDBLCLK() ON_WM_MOUSEMOVE() OnMButtonDblClk OnRButtonDown OnRButtonUp OnRButtonDblClk OnMouseMove 7 비트매스크 MK_CONTROL MK_SHIFT MK_LBUTTON MK_MBUTTON MK_RBUTTON 의미 Ctrl 키가눌렸을때 Shift 키가눌렸을때 마우스왼쪽버튼이눌렸을때 마우스가운데버튼이눌렸을때 마우스오른쪽버튼이눌렸을때 8
클라이언트영역마우스 예 - 마우스버튼클릭시키보드사용여부를확인하기위해 nflags 확인 void CChildView::OnLButtonDown(UINT nflags, CPoint point) if(nflags & MK_SHIFT) m_strouttext = Shift 키를누름 "; // 만약 Shift 키가눌렸다면... CWnd ::OnLButtonDown(nFlags, point); 클라이언트영역마우스 예 - 마우스이동시드래그처리를위해 nflags 확인 nflags & MK_LBUTTON 의값이 0 이아니면마우스와함께왼쪽마우스버튼이눌려졌다는의미 void CChildView::OnLButtonDown(UINT nflags, CPoint point) if ((nflags & MK_LBUTTON) (nflags & MK_RBUTTON)) m_strouttext = 마우스를드래그하고있습니다 "; else m_strouttext = 마우스를이동하였습니다 "; CWnd ::OnLButtonDown(nFlags, point); 9 10 클라이언트영역마우스 예 MM_LOMETRIC 매핑모드에서마우스왼쪽버튼을눌렀을때한변의길이가 2cm 인정사각형을그림 void CChildView::OnLButtonDown(UINT nflags, CPoint point) CClientDC dc(this); dc.setmapmode(mm_lometric); // 매핑모드를바꾼다 CPoint pt = point; // point 객체를복사한다 dc.dptolp(&pt); // 장치좌표를논리좌표로변환 dc.rectangle(pt.x-100, pt.y+100, pt.x+100, pt.y-100); CWnd ::OnLButtonDown(nFlags, point); 마우스캡쳐 용도 마우스캡처를하면마우스커서의위치에관계없이마우스를받을수있다. 관련함수 API 함수 MFC 함수의미 SetCapture() CWnd::SetCapture() 마우스캡처를시작한다. ReleaseCapture() 없음 마우스캡처를해제한다. GetCapture() CWnd::GetCapture() 어느윈도우가현재마우스캡처 를하고있는지알아낸다. 11 12
비클라이언트영역마우스 비클라이언트영역마우스 발생시점 WM_NCLBUTTONDOWN 왼쪽버튼을누를때 WM_NCLBUTTONUP 왼쪽버튼을뗄때 WM_NCLBUTTONDBLCLK 왼쪽버튼을더블클릭할때 WM_NCMBUTTONDOWN 가운데버튼을누를때 WM_NCMBUTTONUP 가운데버튼을뗄때 WM_NCMBUTTONDBLCLK 가운데버튼을더블클릭할때 WM_NCRBUTTONDOWN 오른쪽버튼을누를때 WM_NCRBUTTONUP 오른쪽버튼을뗄때 WM_NCRBUTTONDBLCLK 오른쪽버튼을더블클릭할때 WM_NCMOUSEMOVE 마우스를움직일때 13 비클라이언트영역마우스 비클라이언트영역마우스핸들러 맵매크로핸들러 WM_NCLBUTTONDOWN ON_WM_NCLBUTTONDOWN() OnNcLButtonDown WM_NCLBUTTONUP ON_WM_NCLBUTTONUP() OnNcLButtonUp WM_NCLBUTTONDBLCLK ON_WM_NCLBUTTONDBLCLK() OnNcLButtonDblClk WM_NCMBUTTONDOWN ON_WM_NCMBUTTONDOWN() OnNcMButtonDown WM_NCMBUTTONUP ON_WM_NCMBUTTONUP() OnNcMButtonUp WM_NCMBUTTONDBLCLK ON_WM_NCMBUTTONDBLCLK() OnNcMButtonDblCl k WM_NCRBUTTONDOWN ON_WM_NCRBUTTONDOWN() OnNcRButtonDown WM_NCRBUTTONUP ON_WM_NCRBUTTONUP() OnNcRButtonUp WM_NCRBUTTONDBLCLK ON_WM_NCRBUTTONDBLCLK() OnNcRButtonDblClk WM_NCMOUSEMOVE ON_WM_NCMOUSEMOVE() OnNcMouseMove 14 비클라이언트영역마우스 핸들러형태 비클라이언트영역마우스 nhittest 비클라이언트영역마우스위치 afx_msg void OnNc* (UINT nhittest, CPoint point) ; nhittest 가생성될때의마우스커서위치를나타내는상수값 다음페이지표참조 point 가생성될때의마우스커서위치 ( 스크린좌표 ) 클라이언트좌표로변환하려면 CWnd::ScreenToClient() 함수를사용 상수값 HTCAPTION HTCLIENT HTCLOSE HTHSCROLL HTMENU HTMAXBUTTON 또는 HTZOOM HTMINBUTTON 또는 HTREDUCE HTSYSMENU HTVSCROLL 의미타이틀바클라이언트영역종료버튼가로스크롤바메뉴최대화버튼최소화버튼시스템메뉴세로스크롤바 15 16
MainFrm.cpp void CMainFrame::OnNcLButtonDown(UINT nhittest, CPoint point) // TODO: Add your message handler code here and/or call default if (nhittest == HTCAPTION) AfxMessageBox(" 제목표시줄을클릭하였습니다."); if (nhittest == HTMINBUTTON) AfxMessageBox(" 최소화할수없습니다."); else CFrameWnd::OnNcLButtonDown(nHitTest, point); 17 18 마우스정보와커서관리 마우스정보 int GetSystemMetrics (int nindex) ; 마우스관련 nindex 값 nindex 의미 SM_CMOUSEBUTTONS 마우스버튼의개수를리턴하며마우스가설치되지않은경우에는 0을리턴한다. SM_MOUSEPRESENT 마우스의설치여부를 TRUE 또는 FALSE로리턴한다. SM_SWAPBUTTON 왼쪽과오른쪽버튼의의미가바뀌었으면 TRUE를리턴한다. SM_MOUSEWHEELPRESENT 휠 (Wheel) 마우스이면 TRUE를리턴한다. 마우스정보와커서관리 커서 (Cursor) 마우스의위치를알려주는이미지 커서모양에따라화면의한지점을가리키는위치 (Hot Spot) 를설정 커서선택 표준커서선택 CWinApp::LoadStandardCursor() IDC_ARROW, IDC_CROSS, IDC_WAIT, IDC_SIZEALL, 리소스의사용자정의커서선택 CWinApp::LoadCursor() 커서형태변경 WM_SETCURSOR 윈도우내에서커서가움직일때마다윈도우로보내지는 19 20
마우스정보와커서관리 마우스정보와커서관리 커서변경 HCURSOR SetCursor (HCURSOR hcursor) hcursor 커서리소스를가리키는핸들값 다음두함수의리턴값을대입 CWinApp::LoadStandardCursor() CWinApp::LoadCursor() 커서위치확인 BOOL GetCursorPos( LPPOINT lppoint ) 커서위치변경 BOOL SetCursorPos(int x, int y) 커서위치제한 BOOL ClipCursor (CONST RECT *lprect) lprect 영역안에커서의움직임이제한, null 이면제한해제 커서가움직일수있는사각형의범위 ( 스크린좌표 ) 커서조작함수에서의위치값은모두스크린좌표값의픽셀단위사용 - 스크린좌표값 / 클라이언트영역좌표값변경함수 CWnd::ScreenToClient void ScreenToClient( LPPOINT lppoint ) const; void ScreenToClient( LPRECT lprect ) const; CWnd::ClientToScreen void ClientToScreen( LPPOINT lppoint ) const; void ClientToScreen( LPRECT lprect ) const; 커서움직임의제한을없애고자한다면 lprect에 NULL21 값을사용 22 // 커서이동시발생되는처리함수 BOOL CWinmsgMouseView::OnSetCursor(CWnd* pwnd, UINT nhittest, UINT message) // 클라이언트영역이면커서모양을변경한다. if(nhittest == HTCLIENT) CPoint point; ::GetCursorPos(&point); // 커서의위치를얻는다 ( 스크린좌표 ). ScreenToClient(&point); // 스크린좌표를클라이언트좌표로변환한다. CRect rect1(100, 100, 200, 200); // 기준사각형 1 CRect rect2(300, 100, 400, 200); // 기준사각형 2 if(rect1.ptinrect(point)) // 커서가기준사각형 1 안쪽에있는지확인한다. ::SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR1)); // 사용자정의커서사용 else if(rect2.ptinrect(point)) // 커서가기준사각형 2 안쪽에있는지확인한다. ::SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR3)); // 사용자정의커서사용 else ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS)); // 표준커서사용 return TRUE; return CView::OnSetCursor(pWnd, nhittest, message); 23 // 커서의위치제한 / 해제처리 void CWinmsgMouseView::OnLButtonDblClk(UINT nflags, CPoint point) CRect rect; GetClientRect(&rect); // 클라이언트영역추출 ClientToScreen( &rect); // 클라이언트영역을스크린영역좌표로변환 AfxMessageBox(" 커서영역을클라이언트영역으로제한합니다 "); ::ClipCursor(&rect); // 클라이언트영역으로커서제한 CView::OnLButtonDblClk(nFlags, point); void CWinmsgMouseView::OnRButtonDown(UINT nflags, CPoint point) AfxMessageBox(" 커서영역을제한을해제합니다 "); ::ClipCursor(NULL); // 커서영역제한해제 CView::OnRButtonDown(nFlags, point); 24
키보드기초 키보드처리 윈도우운영체제는키보드와관련된모든변화를형태로프로그램에게전달한다. 키보드전달 키보드는키보드포커스를가진윈도우가받는다. 키보드포커스 활성윈도우또는활성윈도우의자식윈도우가가지는일종의속성 키보드포커스 키보드포커스유형 키보드 스캔코드 캐럿 키보드장치드라이버 시스템대기열 응용프로그램대기열 루프 25 핸들러 26 키보드포커스 키보드포커스변화 WM_SETFOCUS 포커스를얻은활성화된윈도우에게보내는 WM_KILLFOCUS 비활성화되는윈도우에게보내는 WM_SETFOCUS WM_KILLFOCUS WM_SETFOCUS 27 캐럿 (Caret) 관련함수 캐럿 (Caret) 관련함수 함수이름 역할 CreateCaret() 비트맵을이용하여캐럿을생성한다. CreateGrayCaret() 회색사각형모양의캐럿을생성한다. CreateSolidCaret() 검정색사각형모양의캐럿을생성한다. ShowCaret() 캐럿이보이도록한다. HideCaret() 캐럿을숨긴다. GetCaretPos() 캐럿의위치 ( 클라이언트좌표 ) 를얻는다. SetCaretPos() 캐럿의위치 ( 클라이언트좌표 ) 를변경한다. ::DestroyCaret() 캐럿을파괴한다. ::GetCaretBlinkTime() 캐럿이깜박이는간격을얻는다. ::SetCaretBlinkTime() 캐럿이깜박이는간격을설정한다. 28
캐럿 // 캐럿 (caret) 사용예 void CChildView::OnSetFocus(CWnd* poldwnd) CWnd ::OnSetFocus(pOldWnd); CreateSolidCaret(20, 20); SetCaretPos(CPoint(50, 50)); ShowCaret(); // 사각형모양의캐럿생성 // 캐럿의위치설정 // 화면에캐럿을보이기 void CChildView::OnKillFocus(CWnd* pnewwnd) CWnd ::OnKillFocus(pNewWnd); HideCaret(); ::DestroyCaret(); // 캐럿숨기기 // 캐럿삭제 키누름 키누름 (Keystroke Message) 키보드를누르거나떼는동작에의해발생하는 WM_KEYDOWN, WM_KEYUP 키누름종류 WM_KEYDOWN WM_KEYUP WM_SYSKEYDOWN WM_SYSKEYUP 의미 F10, Alt 이외의키를누를때 F10, Alt 를이외의키를뗄때 F10, Alt, Alt + 키조합을누를때 F10, Alt, Alt + 키조합을뗄때 29 30 키누름 키보드핸들러형태 afx_msg void On* (UINT nchar, UINT nrepcnt, UINT nflags) ; nchar 키누름 (WM_KEYDOWN) - 키에할당된가상키코드값 문자 (WM_CHAR) 문자코드 nrepcnt 키를계속누르고있을경우 1보다큰값을가진다. nflags 키와관련된다양한정보를담고있다 (MSDN 참조 ). 31 키누름 가상키코드 운영체제가각키에할당한장치독립적인고유값 <winuser.h> 가상키코드 VK_CANCEL VK_BACK VK_TAB VK_RETURN VK_SHIFT VK_CONTROL VK_MENU VK_PAUSE VK_CAPITAL VK_ESCAPE VK_SPACE VK_PRIOR VK_NEXT VK_END 해당키 Ctrl-Break Backspace Tab Enter Shift Ctrl Alt Pause Caps Lock Esc Spacebar PgUp PgDn End 가상키코드 VK_HOME VK_LEFT VK_UP VK_RIGHT VK_DOWN VK_SNAPSHOT VK_INSERT VK_DELETE VK_0 - VK_9 VK_A - VK_Z VK_F1 - VK_F12 VK_NUMLOCK VK_SCROLL 해당키 Home Print Screen Insert Delete 0 9 A Z F1 - F12 Num Lock Scroll Lock 32
문자 문자 (Character Message) 필요성 -VK_R 키를누른경우? 문자 r R ㄱ ㄲ 가상키코드조합 영문입력모드에서 VK_R 또는 VK_R + Caps Lock + Shift 키를누른경우영문입력모드에서 VK_R + Caps Lock 또는 VK_R + Shift 키를누른경우한글입력모드에서 VK_R 키를누른경우 한글입력모드에서 VK_R + Shift 키를누른경우 문자 문자 -VK_R 키를누른경우 WM_KEYDOWN WM_CHAR WM_KEYUP 문자 - Alt + VK_R 키를누른경우 WM_SYSKEYDOWN WM_SYSKEYDOWN WM_SYSCHAR WM_SYSKEYUP WM_KEYDOWN 33 34 문자 핸들러형태 afx_msg void OnChar (UINT nchar, UINT nrepcnt, UINT nflags) ; afx_msg void OnSysChar (UINT nchar, UINT nrepcnt, UINT nflags) ; nchar 키에해당하는문자코드 (Character Code) 값을가진다. nrepcnt 키를계속누르고있을경우 1 보다큰값을가진다. nflags 키와관련된다양한정보를담고있다 (MSDN 참조 ). 35 문자 키보드예 문자열을입력받고이동키 ( 화살표, pageup/down, Home, End) 를사용하여문자열이동 Document 클래스멤버 입력문자열 (Cstring m_strouttext) View 클래스멤버 출력위치 (Cpoint m_pnow) void CWinmsgKeyView::OnChar(UINT nchar, UINT nrepcnt, UINT nflags) CWinmsgKeyDoc* pdoc = GetDocument();// 도큐먼트의포인터얻음 pdoc->m_strouttext += nchar; // 키보드로입력된문자를문자열에추가 Invalidate(false); // 화면갱신, 변경된부분만다시그림 CView::OnChar(nChar, nrepcnt, nflags); 36
void CWinmsgKeyView::OnKeyDown(UINT nchar, UINT nrepcnt, UINT nflags) switch(nchar) // 가상키코드값 case VK_LEFT: // 왼쪽화살표키를누를때 m_ptnow.x--;break; // 왼쪽으로 1 이동 case VK_RIGHT: // 오른쪽화살표키를누를때 m_ptnow.x++;break; // 오른쪽으로 1 이동 case VK_UP: // 위쪽화살표키를누를때 m_ptnow.y--;break; // 위쪽으로 1 이동 case VK_DOWN: // 아래쪽화살표키를누를때 m_ptnow.y++;break; // 아래쪽으로 1 이동 case VK_PRIOR: // Pageup키를누를때 m_ptnow.y -= 50;break; // 위쪽으로 50 이동 case VK_NEXT: // Pagedown키를누를때 m_ptnow.y += 50;break; // 아래쪽으로 50 이동 case VK_HOME: // Home키를누를때 m_ptnow = CPoint(0, 0);break; // 처음위치로이동 if(m_ptnow.x < 0) // X좌표가 0보다작으면 m_ptnow.x = 0; // m_ptnow.x = 0으로초기화 AfxMessageBox(" 왼쪽으로더이상이동할수없습니다."); // 박스출력 if(m_ptnow.y < 0) // Y좌표가 0보다작으면 m_ptnow.y = 0; // m_ptnow.y = 0으로초기화 AfxMessageBox(" 위쪽으로더이상이동할수없습니다."); // 박스출력 Invalidate(); // 화면갱신 37 CView::OnKeyDown(nChar, nrepcnt, nflags); Practice SimpleMouseDrawing 프로그램을이용하여그림판의도형그리기 ( 선, 사각형, 타원 ) 를구현하라 키보드 SPACEBAR 버튼 (VK_SPACE) 을눌러도형 ( 선, 사각형, 타원 ) 을선택한다 (WM_KEYDOWN) 왼쪽마우스버튼을누를때 (WM_LBUTTONDOWN) 시작점을입력 왼쪽마우스버튼이눌린상태에서움직일때 (WM_MOUSEMOVE) 끝점을입력 도형그리기 왼쪽마우스버튼을뗄때 (WM_LBUTTONUP) 끝점을입력 도형그리기 마우스캡처를사용하여마우스커서의위치에관계없이마우스를받을수있도록한다