//filename:VisualKB.h #define MAX_STRING 12 class CMyApp:public CWinApp{ public: virtual BOOL InitInstance(); }; class CMainWindow:public CWnd { protected: int m_cxChar; //Average character width int m_cyChar; //Character height int m_cyLine; //Vertical line spacing in message box int m_nTextPos; //Index of current character for tabbed output int m_nTabStops[7]; //Tab stop locations for tabbed output int m_nTextLimit; //Maximum width of text in text box int m_nMsgPos; //Current position in m_strMessages array HCURSOR m_hCursorArrow; //Handle of arrow cursor HCURSOR m_hCursorIBeam; //Handle of I-Beam cursor CPoint m_ptTextOrigin; //Origin for drawing input text CPoint m_ptHeaderOrigin; //Origin for drawing header text CPoint m_ptUpperMsgOrigin; //Origin of first line in message box CPoint m_ptLowerMsgOrigin; //Origin of first line in message box CPoint m_ptCaretPos; //Current caret position CRect m_rcTextBox; //Coordinates of text box CRect m_rcTextBoxBorder; //Coordinates of text box border CRect m_rcMsgBoxBorder; //Coordinates of message box border CRect m_rcScroll; //Coordinates of scroll rectangle CString m_strInputText; //Input text CString m_stringMessages[MAX_STRING]; //Array Of message strings public: CMainWindow(); protected: int GetNearestPos(CPoint point); void PositionCaret(CDC * pDC=NULL); void DrawInputText(CDC * pDC); void ShowMessage(LPCTSTR pszMessage,UINT nChar,UINT nRepCnt, UINT nFlags); void DrawMessageHeader(CDC * pDC); void DrawMessage(CDC * pDC); void DrawMessages(CDC * pDC); protected: virtual void PostNcDestroy(); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnPaint (); afx_msg void OnSetFocus(CWnd* pWnd); //old wnd afx_msg void OnKillFocus(CWnd* pWnd); //new wnd afx_msg BOOL OnSetCursor(CWnd *pWnd,UINT nHitTest,UINT message); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags); DECLARE_MESSAGE_MAP() };
//filename:VisualKB.cpp #include <afxwin.h> #include "VisualKB.h" CMyApp myApp; //CMyApp member functions BOOL CMyApp ::InitInstance() { m_pMainWnd = new CMainWindow; m_pMainWnd ->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } ///////////////////////////////////////////////////////// //CMainWindow message map and number functiosn BEGIN_MESSAGE_MAP(CMainWindow,CWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_SETFOCUS() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_SETCURSOR() ON_WM_LBUTTONDOWN() ON_WM_KEYDOWN() ON_WM_KEYUP() ON_WM_SYSKEYDOWN() ON_WM_SYSKEYUP() ON_WM_CHAR() ON_WM_SYSCHAR() END_MESSAGE_MAP() CMainWindow::CMainWindow() { m_nTextPos = 0; m_nMsgPos = 0; m_hCursorArrow = AfxGetApp()->LoadStandardCursor(IDC_ARROW); m_hCursorIBeam = AfxGetApp()->LoadStandardCursor(IDC_IBEAM); //register a WNDCLASS CString strWndClass = AfxRegisterWndClass( 0, NULL, (HBRUSH)(COLOR_3DFACE + 1), AfxGetApp()->LoadStandardIcon(IDI_WINLOGO) ); //create a window CreateEx(0,strWndClass,_T("Visual Keyboard"), WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL ); } int CMainWindow::OnCreate(LPCREATESTRUCT lpCreateStruct) { if(CWnd::OnCreate(lpCreateStruct)==-1) { return -1; } CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); m_cxChar = tm.tmAveCharWidth; m_cyChar = tm.tmHeight; m_cyLine = tm.tmHeight + tm.tmExternalLeading; m_rcTextBoxBorder.SetRect(16,16,(m_cxChar*64)+16, ((m_cyChar*3)/2)+16 ); m_rcTextBox = m_rcTextBoxBorder; m_rcTextBox.InflateRect(-2,-2); m_rcMsgBoxBorder.SetRect(16, (m_cyChar*4)+16, (m_cxChar * 64)+16,(m_cyLine * MAX_STRING)+(m_cyChar * 6)+16 ); m_rcScroll.SetRect(m_cxChar + 16,(m_cyChar * 4)+16, (m_cxChar * 64)+16, (m_cyLine * MAX_STRING ) + (m_cyChar * 6) + 16 ); m_ptTextOrigin.x = m_cxChar + 16; m_ptTextOrigin.y = (m_cyChar /4 )+16; m_ptCaretPos = m_ptTextOrigin; m_nTextLimit = (m_cxChar * 63)+16; m_ptHeaderOrigin.x = m_cxChar + 16; m_ptHeaderOrigin.y = (m_cyChar * 3)+16; m_ptUpperMsgOrigin.x = m_cxChar + 16; m_ptUpperMsgOrigin.y = m_cyChar * 5 + 16; m_ptLowerMsgOrigin.x = m_cxChar + 16; m_ptLowerMsgOrigin.y = (m_cyChar * 5) + m_cyLine * (MAX_STRING -1)+16; m_nTabStops[0] = (m_cxChar * 24) + 16; m_nTabStops[1] = (m_cxChar * 30) + 16; m_nTabStops[2] = (m_cxChar * 36) + 16; m_nTabStops[3] = (m_cxChar * 42) + 16; m_nTabStops[4] = (m_cxChar * 46) + 16; m_nTabStops[5] = (m_cxChar * 50) + 16; m_nTabStops[6] = (m_cxChar * 54) + 16; CRect rect(0,0,m_rcMsgBoxBorder.right + 16, m_rcMsgBoxBorder.bottom + 16); CalcWindowRect(&rect); SetWindowPos(NULL,0,0,rect.Width() ,rect.Height(), SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW); return 0; } void CMainWindow::PostNcDestroy() { delete this; } void CMainWindow::OnPaint() { CPaintDC dc(this); dc.DrawEdge(m_rcTextBoxBorder,EDGE_SUNKEN,BF_RECT); dc.DrawEdge(m_rcMsgBoxBorder,EDGE_SUNKEN,BF_RECT); DrawInputText(&dc); DrawMessageHeader(&dc); DrawMessage(&dc); } void CMainWindow::OnSetFocus(CWnd* pWnd){ CreateSolidCaret(max(2,::GetSystemMetrics(SM_CXBORDER)), m_cyChar); SetCaretPos(m_ptCaretPos); ShowCaret(); } void CMainWindow::OnKillFocus(CWnd* pWnd){ HideCaret(); m_ptCaretPos = GetCaretPos(); ::DestroyCaret(); } BOOL CMainWindow::OnSetCursor(CWnd *pWnd,UINT nHitTest,UINT message) { if(nHitTest == HTCLIENT) { DWORD dwPos = ::GetMessagePos(); CPoint point(LOWORD(dwPos),HIWORD(dwPos)); ScreenToClient(&point); ::SetCursor(m_rcTextBox.PtInRect(point)? m_hCursorIBeam:m_hCursorArrow); return TRUE; } return CWnd::OnSetCursor(pWnd,nHitTest,message); } void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point) { if(m_rcTextBox.PtInRect(point)) { m_nTextPos = GetNearestPos(point); PositionCaret(); } } void CMainWindow::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_KEYDOWN"),nChar,nRepCnt,nFlags); switch (nChar) { case VK_LEFT: if(m_nTextPos !=0){ m_nTextPos --; PositionCaret(); } break; case VK_RIGHT: if(m_nTextPos != m_strInputText.GetLength()) { m_nTextPos++; PositionCaret(); } break; case VK_HOME: m_nTextPos = 0; PositionCaret(); break; case VK_END: m_nTextPos = m_strInputText.GetLength(); PositionCaret(); break; } } void CMainWindow::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_CHAR"),nChar,nRepCnt,nFlags); CClientDC dc(this); switch (nChar) { case VK_ESCAPE: case VK_RETURN: m_strInputText.Empty(); m_nTextPos = 0; break; case VK_BACK: if(m_nTextPos != 0) { m_strInputText = m_strInputText.Left(m_nTextPos-1) +m_strInputText.Right(m_strInputText.GetLength() - m_nTextPos); m_nTextPos--; } break; default: if((nChar>=0) && (nChar <= 31)) return; if(m_nTextPos == m_strInputText.GetLength()) { m_strInputText += nChar; m_nTextPos ++; } else m_strInputText.SetAt(m_nTextPos++,nChar); CSize size = dc.GetTextExtent(m_strInputText, m_strInputText.GetLength()); if((m_ptTextOrigin.x + size.cx) > m_nTextLimit) { m_strInputText = nChar; m_nTextPos = 1; } break; } HideCaret(); DrawInputText(&dc); PositionCaret(&dc); ShowCaret(); } void CMainWindow::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_KEYUP"),nChar,nRepCnt,nFlags); CWnd::OnKeyUp(nChar,nRepCnt,nFlags); } void CMainWindow::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_SYSKEYDOWN"),nChar,nRepCnt,nFlags); CWnd::OnSysKeyDown(nChar,nRepCnt,nFlags); } void CMainWindow::OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_SYSCHAR"),nChar,nRepCnt,nFlags); CWnd::OnSysChar(nChar,nRepCnt,nFlags); } void CMainWindow::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { ShowMessage(_T("WM_SYSKEYUP"),nChar,nRepCnt,nFlags); CWnd::OnSysKeyUp(nChar,nRepCnt,nFlags); } void CMainWindow :: PositionCaret(CDC * pDC/* =NULL */) { BOOL bRelease = FALSE; if(pDC == NULL){ pDC = GetDC(); bRelease = true; } CPoint point = m_ptTextOrigin; CString string = m_strInputText.Left(m_nTextPos); point.x += (pDC ->GetTextExtent(string,string.GetLength())).cx; SetCaretPos(point); if(bRelease) ReleaseDC(pDC); } int CMainWindow::GetNearestPos(CPoint point) { if(point.x <= m_ptTextOrigin.x) return 0; CClientDC dc(this); int nLen = m_strInputText.GetLength(); if(point.x >= (m_ptTextOrigin.x+dc.GetTextExtent(m_strInputText,nLen).cx)) return nLen; int i=0; int nPrevChar = m_ptTextOrigin.x; int nNextChar = m_ptTextOrigin.x; while(nNextChar < point.x){ i++; nPrevChar = nNextChar; nNextChar = m_ptTextOrigin.x + dc.GetTextExtent(m_strInputText.Left(i),i).cx; } return point.x - nPrevChar < nNextChar - point.x ? i-1 : i ; } void CMainWindow::DrawInputText(CDC * pDC) { pDC ->ExtTextOut(m_ptTextOrigin.x,m_ptTextOrigin.y, ETO_OPAQUE,m_rcTextBox,m_strInputText,NULL); } void CMainWindow::ShowMessage(LPCTSTR pszMessage,UINT nChar,UINT nRepCnt, UINT nFlags) { CString string; string.Format(_T("%s\t %u\t %u\t %u\t %u\t %u\t %u\t %u"), pszMessage,nChar,nRepCnt,nFlags & 0xFF, (nFlags >> 8 ) & 0x01, (nFlags >> 13) & 0x01, (nFlags >> 14) & 0x01, (nFlags >> 15) & 0x01 ); ScrollWindow(0,-m_cyLine,&m_rcScroll); ValidateRect(m_rcScroll); CClientDC dc(this); dc.SetBkColor((COLORREF)::GetSysColor(COLOR_3DFACE)); m_stringMessages[m_nMsgPos] = string; dc.TabbedTextOut(m_ptLowerMsgOrigin.x,m_ptLowerMsgOrigin.y, m_stringMessages[m_nMsgPos],m_stringMessages[m_nMsgPos].GetLength(), sizeof(m_nTabStops),m_nTabStops , m_ptLowerMsgOrigin.x); if(++m_nMsgPos == MAX_STRING) m_nMsgPos = 0; } void CMainWindow ::DrawMessageHeader(CDC * pDC) { static CString string = _T("Message\tChar\tRep\tScan\tExt\tCan\tPrv\tTran"); pDC->SetBkColor((COLORREF)::GetSysColor(COLOR_3DFACE)); pDC->TabbedTextOut(m_ptHeaderOrigin.x,m_ptHeaderOrigin.y, string,string.GetLength(),sizeof(m_nTabStops),m_nTabStops,m_ptHeaderOrigin.x); } void CMainWindow::DrawMessage(CDC * pDC) { int nPos = m_nMsgPos; pDC->SetBkColor((COLORREF)::GetSysColor(COLOR_3DFACE)); for(int i=0;i<MAX_STRING;i++){ pDC->TabbedTextOut(m_ptUpperMsgOrigin.x, m_ptUpperMsgOrigin.y + m_cyLine*i, m_stringMessages[nPos], m_stringMessages[nPos].GetLength(), sizeof(m_nTabStops),m_nTabStops,m_ptUpperMsgOrigin.x); if(++nPos == MAX_STRING) nPos = 0; } }