Win32 键盘事件 - 击键消息、字符消息、插入符号(光标)

分类: Win32 SDK 4093人阅读 评论(0) 收藏 举报

目录(?)[+]

注:以下内容为学习笔记,多数是从书本、资料中得来,只为加深印象,及日后参考。然而本人表达能力较差,写的不好。因非翻译、非转载,只好选原创,但多数乃摘抄,实为惭愧。但若能帮助一二访客,幸甚!


以下内容主要来自《Windows 程序设计》

1.焦点

程序用于从消息队列中读取消息的MSG结构中包含一个hwnd字段。此字段指出了接收消息的窗口句柄。消息循环中的DispatchMessage函数传送消息给需要该消息的窗口过程。

接收到这个键盘事件的窗口称为有输入焦点的窗口。

有时没有窗口具有输入焦点。这种情况发生在所以程序都最小化时。

窗口过程通过捕获WM_SETFOCUS和WM_KILLFOCUS消息来确定自己的窗口是否具有输入焦点。


2.队列和同步

当用户按下和释放键盘上的一个键时,Windows和键盘设备驱动程序将硬件扫描码转换为格式化后的消息。但是这些消息并不立即被放入应用程序消息队列,而是由Windows把这些消息存储在系统消息队列中。系统消息队列是一个单独的消息队列,它被Windows用来初步存储用户从键盘和鼠标输入的消息。仅当Windows应用程序完成了对当前一个用户输入消息的处理后,Windows才从系统消息队列中取出下一条消息,并把它放入应用程序消息队列。


3.击键消息

当用户按下一个键时,Windows将WM_KEYDOWN或WM_SYSKEYDOWN消息放入具有输入焦点的消息队列中。当该键被释放时,Windows把WM_KEYUP或WM_SYSKEYUP消息放入相应的消息队列中。其中SYS代表系统,它表明该击键对Windows比对应用程序更加重要。

虚拟键代码存储在WM_KEYDOWN等消息的wParam参数中,确定哪个键被按下或被释放。

当处理击键消息时,可能需要知道是否有转义键(Shift、Ctrl和Alt)或切换键(Caps Lock、Num Lock和Scroll Lock)键被按下。

可以用如下方式:

iState = GetKeyState(VK_SHIFT);

给前面的SYSMETS代码(http://blog.csdn.net/guzhou_diaoke/article/details/8155740   7.滚动条)中添加键盘处理功能:

简单方法:为窗口过程增加WM_KEYDOWN逻辑

更好的方法:把每一个WM_KEYDOWN消息转换为等同的WM_VSCROLL或WM_HSCROLL消息。可以使用:

SendMessage(hwnd, message, wParam, lParam);

当你调用SendMessage函数时,Windows调用窗口句柄hwnd的窗口过程,同时把四个函数变量传递给他。当窗口过程处理完此消息,Windows把控制权还给紧跟着SendMessage调用的下一条语句。

  1. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  2. {  
  3.     // cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度  
  4.     // 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍  
  5.     static int  cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth, iVscrollPos;   
  6.     HDC         hdc;  
  7.     int         i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd;  
  8.     PAINTSTRUCT ps;  
  9.     SCROLLINFO  si;  
  10.     TCHAR       szBuffer[10];  
  11.     TEXTMETRIC  tm;   
  12.   
  13.     switch (message)  
  14.     {  
  15.     case WM_CREATE:  
  16.         hdc = GetDC(hwnd);  
  17.           
  18.         GetTextMetrics(hdc, &tm);       // 获取系统默认字体的尺寸  
  19.         cxChar = tm.tmAveCharWidth;  
  20.         // tmPitchAndFamily为1表示变宽字体,为0表示等宽字体  
  21.         cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;  
  22.         cyChar = tm.tmHeight + tm.tmExternalLeading;  
  23.   
  24.         ReleaseDC(hwnd, hdc);  
  25.   
  26.         iMaxWidth = 40*cxChar + 22*cxCaps;  
  27.         return 0;  
  28.   
  29.     case WM_SIZE:  
  30.         cxClient = LOWORD(lParam);  
  31.         cyClient = HIWORD(lParam);  
  32.           
  33.         si.cbSize   = sizeof(si);  
  34.         si.fMask    = SIF_RANGE | SIF_PAGE;  
  35.   
  36.         si.nMin     = 0;  
  37.         si.nMax     = NUMLINES-1;  
  38.         si.nPage    = cyClient / cyChar;  
  39.         SetScrollInfo(hwnd, SB_VERT, &si, TRUE);  
  40.   
  41.         si.cbSize   = sizeof(si);  
  42.         si.fMask    = SIF_RANGE | SIF_PAGE;  
  43.   
  44.         si.nMin     = 0;  
  45.         si.nMax     = 2 + iMaxWidth/cxChar;  
  46.         si.nPage    = cxClient / cxChar;  
  47.         SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);  
  48.   
  49.         return 0;  
  50.           
  51.     case WM_VSCROLL:  
  52.         si.cbSize   = sizeof(si);  
  53.         si.fMask    = SIF_ALL;  
  54.   
  55.         GetScrollInfo(hwnd, SB_VERT, &si);  
  56.         iVertPos = si.nPos;  
  57.   
  58.         switch (LOWORD(wParam))  
  59.         {  
  60.         case SB_TOP:  
  61.             si.nPos = si.nMin;  
  62.             break;  
  63.   
  64.         case SB_BOTTOM:  
  65.             si.nPos = si.nMax;  
  66.             break;  
  67.   
  68.         case SB_LINEUP:  
  69.             si.nPos -= 1;  
  70.             break;  
  71.   
  72.         case SB_LINEDOWN:  
  73.             si.nPos += 1;  
  74.             break;  
  75.   
  76.         case SB_PAGEUP:  
  77.             si.nPos -= si.nPage;  
  78.             break;  
  79.   
  80.         case SB_PAGEDOWN:  
  81.             si.nPos += si.nPage;  
  82.             break;  
  83.   
  84.         case SB_THUMBTRACK:  
  85.             si.nPos = si.nTrackPos;  
  86.             break;  
  87.   
  88.         default:  
  89.             break;  
  90.         }  
  91.   
  92.         si.fMask = SIF_POS;  
  93.         SetScrollInfo(hwnd, SB_VERT, &si, TRUE);  
  94.         GetScrollInfo(hwnd, SB_VERT, &si);  
  95.   
  96.         if (si.nPos != iVertPos)  
  97.         {  
  98.             ScrollWindow(hwnd, 0, cyChar*(iVertPos-si.nPos), NULL, NULL);  
  99.             UpdateWindow(hwnd);  
  100.         }  
  101.         return 0;  
  102.   
  103.     case WM_HSCROLL:  
  104.         si.cbSize   = sizeof(si);  
  105.         si.fMask    = SIF_ALL;  
  106.   
  107.         GetScrollInfo(hwnd, SB_HORZ, &si);  
  108.         iHorzPos = si.nPos;  
  109.   
  110.         switch (LOWORD(wParam))  
  111.         {  
  112.         case SB_LINELEFT:  
  113.             si.nPos -= 1;  
  114.             break;  
  115.   
  116.         case SB_LINERIGHT:  
  117.             si.nPos += 1;  
  118.             break;  
  119.   
  120.         case SB_PAGELEFT:  
  121.             si.nPos -= si.nPage;  
  122.             break;  
  123.   
  124.         case SB_PAGERIGHT:  
  125.             si.nPos += si.nPage;  
  126.             break;  
  127.   
  128.         case SB_THUMBPOSITION:  
  129.             si.nPos = si.nTrackPos;  
  130.             break;  
  131.   
  132.         default:  
  133.             break;  
  134.         }  
  135.   
  136.         si.fMask = SIF_POS;  
  137.         SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);  
  138.         GetScrollInfo(hwnd, SB_HORZ, &si);  
  139.   
  140.         if (si.nPos != iHorzPos)  
  141.         {  
  142.             ScrollWindow(hwnd, cxChar*(iHorzPos-si.nPos), 0, NULL, NULL);  
  143.             UpdateWindow(hwnd);  
  144.         }  
  145.         return 0;  
  146.   
  147.     case WM_KEYDOWN:  
  148.         switch (wParam)  
  149.         {  
  150.         case VK_HOME:  
  151.             SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);  
  152.             break;  
  153.   
  154.         case VK_END:  
  155.             SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);  
  156.             break;  
  157.   
  158.         case VK_PRIOR:  
  159.             SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);  
  160.             break;  
  161.   
  162.         case VK_NEXT:  
  163.             SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);  
  164.             break;  
  165.   
  166.         case VK_UP:  
  167.             SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);  
  168.             break;  
  169.   
  170.         case VK_DOWN:  
  171.             SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);  
  172.             break;  
  173.   
  174.         case VK_LEFT:  
  175.             SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0);  
  176.             break;  
  177.   
  178.         case VK_RIGHT:  
  179.             SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0);  
  180.             break;  
  181.         }  
  182.         return 0;  
  183.   
  184.     case WM_PAINT:  
  185.         hdc = BeginPaint(hwnd, &ps);  
  186.   
  187.         si.cbSize = sizeof(si);  
  188.         si.fMask = SIF_POS;  
  189.           
  190.         GetScrollInfo(hwnd, SB_VERT, &si);  
  191.         iVertPos = si.nPos;  
  192.   
  193.         GetScrollInfo(hwnd, SB_HORZ, &si);  
  194.         iHorzPos = si.nPos;  
  195.   
  196.         iPaintBeg = max(0, iVertPos + ps.rcPaint.top/cyChar);  
  197.         iPaintEnd = min(NUMLINES-1, iVertPos + ps.rcPaint.bottom/cyChar);  
  198.   
  199.         for (i = iPaintBeg; i <= iPaintEnd; i++)  
  200.         {  
  201.             x = cxChar * (1-iHorzPos);  
  202.             y = cyChar * (i-iVertPos);  
  203.   
  204.             TextOut(hdc, x, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));  
  205.   
  206.             TextOut(hdc, x + 22*cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));  
  207.   
  208.             SetTextAlign(hdc, TA_RIGHT | TA_TOP);  
  209.   
  210.             TextOut(hdc, x + 22*cxCaps + 40*cxChar, y, szBuffer, wsprintf(szBuffer, TEXT("%5d"),   
  211.                 GetSystemMetrics(sysmetrics[i].iIndex)));  
  212.   
  213.             // 将对齐方式设回正常方式  
  214.             SetTextAlign(hdc, TA_LEFT | TA_TOP);  
  215.         }  
  216.   
  217.         EndPaint(hwnd, &ps);  
  218.         return 0;  
  219.   
  220.     case WM_DESTROY:  
  221.         PostQuitMessage(0);  
  222.         return 0;  
  223.     }  
  224.   
  225.     return DefWindowProc(hwnd, message, wParam, lParam);  
  226. }  


有键盘了,就差鼠标了~很快会有的。


4.字符消息

通过转义状态信息可把击键消息转换为字符消息。

GetMessage从消息队列中取出下一条消息;

TranslateMessage负责把击键消息转换为字符消息;

DispatchMessage调用此消息的窗口过程。


5.消息排序

假如Caps Lock没有锁定,按下再释放A,相应窗口过程会接收:

1)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

2)WM_CHAR:  'a'的字符编码(0x61)

3)WM_KEYUP: 'A' 的虚拟键代码(0x41)


按下Shift+A,释放A,再释放Shift:

1)WM_KEYDOWN:虚拟键代码VK_SHIFT(0x10)

2)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

3)WM_CHAR:  'A' 的字符编码(0x41)

4)WM_KEYUP: 'A' 的虚拟键代码(0x41)

5)WM_UP:虚拟键代码VK_SHIFT(0x10)


连续按住A:

1)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

2)WM_CHAR:  'a'的字符编码(0x61)

3)WM_KEYDOWN:’A‘ 的虚拟键代码(0x41)

4)WM_CHAR:  'a'的字符编码(0x61)

……

n)WM_KEYUP: 'A' 的虚拟键代码(0x41)


6.控制字符的处理

按照以下基本规则来处理击键和字符消息:如果你需要读取输入到窗口中的键盘字符,就处理WM_CHAR消息;如果你需要读取光标键、功能键、Delete键、Insert键、Shift键、Ctrl键和Alt键,则处理WM_KEYDOWN消息。


  1. /*--------------------------------------------------------------------------- 
  2.     keyView.cpp -- Displays keyboard and character messages 
  3. ----------------------------------------------------------------------------*/  
  4.   
  5. /*----------------------------------------------------------------------------------- 
  6.     SysMets4.cpp -- System Metrics Display Program ver4 use keyboard 
  7.  *----------------------------------------------------------------------------------*/  
  8.   
  9. #include <windows.h>  
  10.   
  11. LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM);  
  12.   
  13. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)  
  14. {  
  15.     static TCHAR    szAppName[] = TEXT("KeyView1");  
  16.     HWND            hwnd;  
  17.     MSG             msg;  
  18.     WNDCLASS        wndclass;  
  19.   
  20.     wndclass.style          = CS_HREDRAW | CS_VREDRAW;  
  21.     wndclass.lpfnWndProc    = WndProc;  
  22.     wndclass.cbClsExtra     = 0;  
  23.     wndclass.cbWndExtra     = 0;  
  24.     wndclass.hInstance      = hInstance;  
  25.     wndclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);  
  26.     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);  
  27.     wndclass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  28.     wndclass.lpszMenuName   = NULL;  
  29.     wndclass.lpszClassName  = szAppName;  
  30.   
  31.     if (!RegisterClass(&wndclass))  
  32.     {  
  33.         MessageBox(NULL, TEXT("This program requires windows NT!"), szAppName, MB_ICONERROR);  
  34.         return 0;  
  35.     }  
  36.   
  37.     hwnd = CreateWindow(szAppName,                                      // window class name  
  38.                         TEXT("Keyboard Message Viewer #1"),             // window caption  
  39.                         WS_OVERLAPPEDWINDOW,                            // window style  
  40.                         CW_USEDEFAULT,                                  // initial x position  
  41.                         CW_USEDEFAULT,                                  // initial y position  
  42.                         CW_USEDEFAULT,                                  // initial x size  
  43.                         CW_USEDEFAULT,                                  // initial y size  
  44.                         NULL,                                           // parent window handle  
  45.                         NULL,                                           // window menu handle  
  46.                         hInstance,                                      // program instance handle  
  47.                         NULL);                                          // creation parameters  
  48.   
  49.     ShowWindow(hwnd, iCmdShow);  
  50.     UpdateWindow(hwnd);  
  51.   
  52.     while (GetMessage(&msg, NULL, 0, 0))  
  53.     {  
  54.         TranslateMessage(&msg);  
  55.         DispatchMessage(&msg);  
  56.     }  
  57.   
  58.     return msg.wParam;  
  59. }  
  60.   
  61. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  62. {  
  63.     // cxChar平均字符宽度,cyChar字符的总高度(包括外部间距),cxCaps大写字符的平均宽度  
  64.     // 等宽字体中,cxCaps等于cxChar,变宽字体中,cxCaps等于cxChar的1.5倍  
  65.     static int      cxChar, cyChar, cxClient, cyClient, cxClientMax, cyClientMax;  
  66.     static int      cLinesMax, cLines;  
  67.     static PMSG     pmsg;  
  68.     static RECT     rectScroll;  
  69.     static TCHAR szTop[] = TEXT ("Message        Key       Char     ")  
  70.                             TEXT ("Repeat Scan Ext ALT Prev Tran") ;  
  71.      static TCHAR szUnd[] = TEXT ("_______        ___       ____     ")  
  72.                             TEXT ("______ ____ ___ ___ ____ ____") ;  
  73.   
  74.     static TCHAR*   szFormat[2] = {  
  75.         TEXT("%-13s %3d %-15s%c%6u %4d %3s %3s %4s %4s"),  
  76.         TEXT("%-13s            0x%04X%1s%c %6u %4d %3s %3s %4s %4s") };  
  77.     static TCHAR*   szYes   = TEXT("Yes");  
  78.     static TCHAR*   szNo    = TEXT("No");  
  79.     static TCHAR*   szDown  = TEXT("Down");  
  80.     static TCHAR*   szUp    = TEXT("Up");  
  81.   
  82.     static TCHAR*   szMessage[] = {  
  83.         TEXT("WM_KEYDOWN"),     TEXT("WM_KEYUP"),  
  84.         TEXT("WM_CHAR"),        TEXT("WM_DEADCHAR"),  
  85.         TEXT("WM_SYSKEYDOWN"),  TEXT("WM_SYSKEYUP"),  
  86.         TEXT("WM_SYSCHAR"),     TEXT("WM_SYSDEADCHAR") };  
  87.   
  88.     HDC         hdc;  
  89.     int         i, iType;  
  90.     PAINTSTRUCT ps;  
  91.     TCHAR       szBuffer[128], szKeyName[32];  
  92.     TEXTMETRIC  tm;   
  93.   
  94.     switch (message)  
  95.     {  
  96.     case WM_CREATE:  
  97.     case WM_DISPLAYCHANGE:  
  98.         cxClientMax = GetSystemMetrics(SM_CXMAXIMIZED);  
  99.         cyClientMax = GetSystemMetrics(SM_CYMAXIMIZED);  
  100.   
  101.         hdc = GetDC(hwnd);  
  102.           
  103.         SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));  
  104.         GetTextMetrics(hdc, &tm);       // 获取系统默认字体的尺寸  
  105.         cxChar = tm.tmAveCharWidth;  
  106.         cyChar = tm.tmHeight;  
  107.   
  108.         ReleaseDC(hwnd, hdc);  
  109.   
  110.         if (pmsg)  
  111.             free(pmsg);  
  112.   
  113.         cLinesMax = cyClientMax / cyChar;  
  114.         pmsg = (PMSG)malloc(cLinesMax * sizeof(MSG));  
  115.         cLines = 0;  
  116.   
  117.         //return 0;  
  118.   
  119.     case WM_SIZE:  
  120.         if (message == WM_SIZE)  
  121.         {  
  122.             cxClient = LOWORD(lParam);  
  123.             cyClient = HIWORD(lParam);  
  124.         }  
  125.           
  126.         rectScroll.left     = 0;  
  127.         rectScroll.right    = cxClient;  
  128.         rectScroll.top      = cyChar;  
  129.         rectScroll.bottom   = cyChar * (cyClient / cyChar);  
  130.   
  131.         InvalidateRect(hwnd, NULL, TRUE);  
  132.   
  133.         return 0;  
  134.           
  135.     case WM_KEYDOWN:  
  136.     case WM_KEYUP:  
  137.     case WM_CHAR:  
  138.     case WM_DEADCHAR:  
  139.     case WM_SYSKEYDOWN:  
  140.     case WM_SYSKEYUP:  
  141.     case WM_SYSCHAR:  
  142.     case WM_SYSDEADCHAR:  
  143.         for (i = cLinesMax-1; i > 0; i--)  
  144.         {  
  145.             pmsg[i] = pmsg[i-1];  
  146.         }  
  147.   
  148.         pmsg[0].hwnd    = hwnd;  
  149.         pmsg[0].message = message;  
  150.         pmsg[0].wParam  = wParam;  
  151.         pmsg[0].lParam  = lParam;  
  152.   
  153.         cLines = min(cLines + 1, cLinesMax);  
  154.   
  155.         ScrollWindow(hwnd, 0, -cyChar, &rectScroll, &rectScroll);  
  156.         break;  
  157.       
  158.   
  159.     case WM_PAINT:  
  160.         hdc = BeginPaint(hwnd, &ps);  
  161.   
  162.         SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));  
  163.         SetBkMode(hdc, TRANSPARENT);  
  164.         TextOut(hdc, 0, 0, szTop, lstrlen(szTop));  
  165.         TextOut(hdc, 0, 0, szUnd, lstrlen(szUnd));  
  166.   
  167.         for (i = 0; i < min(cLines, cyClient / cyChar - 1); i++)  
  168.         {  
  169.             iType = pmsg[i].message == WM_CHAR ||  
  170.                     pmsg[i].message == WM_SYSCHAR ||  
  171.                     pmsg[i].message == WM_DEADCHAR ||  
  172.                     pmsg[i].message == WM_SYSDEADCHAR;  
  173.   
  174.             GetKeyNameText(pmsg[i].lParam, szKeyName, sizeof(szKeyName) / sizeof(TCHAR));  
  175.   
  176.             TextOut(hdc, 0, (cyClient/cyChar - 1 - i) * cyChar, szBuffer,   
  177.                 wsprintf(szBuffer, szFormat[iType],  
  178.                     szMessage[pmsg[i].message - WM_KEYFIRST],  
  179.                     pmsg[i].wParam,  
  180.                     (PTSTR)(iType ? TEXT(" ") : szKeyName),  
  181.                     (TCHAR)(iType ? pmsg[i].wParam: ' '),  
  182.                     LOWORD(pmsg[i].lParam),  
  183.                     HIWORD(pmsg[i].lParam) & 0xFF,  
  184.                     0x01000000 & pmsg[i].lParam ? szYes : szNo,  
  185.                     0x20000000 & pmsg[i].lParam ? szYes : szNo,  
  186.                     0x40000000 & pmsg[i].lParam ? szDown: szUp,  
  187.                     0x80000000 & pmsg[i].lParam ? szUp  : szDown));  
  188.         }  
  189.   
  190.         EndPaint(hwnd, &ps);  
  191.         return 0;  
  192.   
  193.     case WM_DESTROY:  
  194.         PostQuitMessage(0);  
  195.         return 0;  
  196.     }  
  197.   
  198.     return DefWindowProc(hwnd, message, wParam, lParam);  
  199. }  



7.插入符号(就是平时说的光标)

插入符号指明你输入的下一个字符将出现在屏幕上的位置。

相关函数:

CreateCaret:创建和窗口关联的插入符号

SetCaretPos:设置窗口内的插入符号的位置

ShowCaret:显式插入符号

HideCaret:隐藏插入符号

DestroyCaret:销毁插入符号

GetCaretPos:获取插入符号位置

GetCaretBlinkTime、SetCaretBlinkTime:获取、设置插入符号闪烁时间


使用插入符号主要规则:在窗口过程处理WM_SETFOCUS消息时调用CreateCaret,处理WM_KILLFOCUS消息时调用DestroyCaret函数。

创建的插入符号是隐藏的,必须调用ShowCaret使之可见。

要在窗口内绘制某些东西时,它必须调用HideCaret隐藏插入符号。结束绘制后,再调用ShowCaret显式插入符号。

HideCaret效果是叠加的。


一个简单的文本编辑器雏形:

  1. /*---------------------------------------------------------------------------- 
  2.     typer.cpp -- Typing Program 
  3. ----------------------------------------------------------------------------*/  
  4.   
  5. /*--------------------------------------------------------------------------- 
  6.     keyView.cpp -- Displays keyboard and character messages 
  7. ----------------------------------------------------------------------------*/  
  8.   
  9. /*----------------------------------------------------------------------------------- 
  10.     SysMets4.cpp -- System Metrics Display Program ver4 use keyboard 
  11.  *----------------------------------------------------------------------------------*/  
  12.   
  13. #include <windows.h>  
  14.   
  15. LRESULT CALLBACK WndProc(HWNDUINTWPARAMLPARAM);  
  16.   
  17. #define BUFFER(x, y)    *(pBuffer + y*cxBuffer + x)  
  18.   
  19. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)  
  20. {  
  21.     static TCHAR    szAppName[] = TEXT("Typer");  
  22.     HWND            hwnd;  
  23.     MSG             msg;  
  24.     WNDCLASS        wndclass;  
  25.   
  26.     wndclass.style          = CS_HREDRAW | CS_VREDRAW;  
  27.     wndclass.lpfnWndProc    = WndProc;  
  28.     wndclass.cbClsExtra     = 0;  
  29.     wndclass.cbWndExtra     = 0;  
  30.     wndclass.hInstance      = hInstance;  
  31.     wndclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);  
  32.     wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);  
  33.     wndclass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);  
  34.     wndclass.lpszMenuName   = NULL;  
  35.     wndclass.lpszClassName  = szAppName;  
  36.   
  37.     if (!RegisterClass(&wndclass))  
  38.     {  
  39.         MessageBox(NULL, TEXT("This program requires windows NT!"), szAppName, MB_ICONERROR);  
  40.         return 0;  
  41.     }  
  42.   
  43.     hwnd = CreateWindow(szAppName,                                      // window class name  
  44.                         TEXT("Typer"),                                  // window caption  
  45.                         WS_OVERLAPPEDWINDOW,                            // window style  
  46.                         CW_USEDEFAULT,                                  // initial x position  
  47.                         CW_USEDEFAULT,                                  // initial y position  
  48.                         CW_USEDEFAULT,                                  // initial x size  
  49.                         CW_USEDEFAULT,                                  // initial y size  
  50.                         NULL,                                           // parent window handle  
  51.                         NULL,                                           // window menu handle  
  52.                         hInstance,                                      // program instance handle  
  53.                         NULL);                                          // creation parameters  
  54.   
  55.     ShowWindow(hwnd, iCmdShow);  
  56.     UpdateWindow(hwnd);  
  57.   
  58.     while (GetMessage(&msg, NULL, 0, 0))  
  59.     {  
  60.         TranslateMessage(&msg);  
  61.         DispatchMessage(&msg);  
  62.     }  
  63.   
  64.     return msg.wParam;  
  65. }  
  66.   
  67. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  68. {  
  69.     static DWORD    dwCharSet = DEFAULT_CHARSET;  
  70.     static int      cxChar, cyChar, cxClient, cyClient, cxBuffer, cyBuffer, xCaret, yCaret;  
  71.     static TCHAR*   pBuffer = NULL;  
  72.   
  73.     int             x, y, i;  
  74.     HDC             hdc;  
  75.     PAINTSTRUCT     ps;  
  76.     TEXTMETRIC      tm;   
  77.   
  78.     switch (message)  
  79.     {  
  80.     case WM_INPUTLANGCHANGE:  
  81.         dwCharSet = wParam;  
  82.   
  83.     case WM_CREATE:  
  84.         hdc = GetDC(hwnd);  
  85.           
  86.         SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));  
  87.         GetTextMetrics(hdc, &tm);  
  88.         cxChar = tm.tmAveCharWidth;  
  89.         cyChar = tm.tmHeight;  
  90.           
  91.         DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));  
  92.         ReleaseDC(hwnd, hdc);  
  93.   
  94.     case WM_SIZE:  
  95.         if (message == WM_SIZE)  
  96.         {  
  97.             cxClient = LOWORD(lParam);  
  98.             cyClient = HIWORD(lParam);  
  99.         }  
  100.           
  101.         cxBuffer = max(1, cxClient/cxChar);  
  102.         cyBuffer = max(1, cyClient/cyChar);  
  103.   
  104.         if (pBuffer != NULL)  
  105.             free(pBuffer);  
  106.   
  107.         pBuffer = (TCHAR *)malloc(sizeof(TCHAR) * cxBuffer * cyBuffer);  
  108.   
  109.         for (y = 0; y < cyBuffer; y++)  
  110.             for (x = 0; x < cxBuffer; x++)  
  111.                 BUFFER(x, y) = ' ';  
  112.   
  113.         xCaret = 0;  
  114.         yCaret = 0;  
  115.   
  116.         if (hwnd == GetFocus())  
  117.             SetCaretPos(xCaret * cxChar, yCaret * cyChar);  
  118.   
  119.         InvalidateRect(hwnd, NULL, TRUE);  
  120.         return 0;  
  121.   
  122.     case WM_SETFOCUS:  
  123.         CreateCaret(hwnd, NULL, cxChar, cyChar);  
  124.         SetCaretPos(xCaret*cxChar, yCaret*cyChar);  
  125.         ShowCaret(hwnd);  
  126.         return 0;  
  127.   
  128.     case WM_KILLFOCUS:  
  129.         HideCaret(hwnd);  
  130.         DestroyCaret();  
  131.         return 0;  
  132.           
  133.     case WM_KEYDOWN:  
  134.         switch (wParam)  
  135.         {  
  136.         case VK_HOME:  
  137.             xCaret = 0;  
  138.             break;  
  139.   
  140.         case VK_END:  
  141.             xCaret = cxBuffer - 1;  
  142.             break;  
  143.   
  144.         case VK_PRIOR:  
  145.             yCaret = 0;  
  146.             break;  
  147.   
  148.         case VK_NEXT:  
  149.             yCaret = cyBuffer - 1;  
  150.             break;  
  151.   
  152.         case VK_LEFT:  
  153.             xCaret = max(xCaret-1, 0);  
  154.             break;  
  155.   
  156.         case VK_RIGHT:  
  157.             xCaret = min(xCaret+1, cxBuffer-1);  
  158.             break;  
  159.   
  160.         case VK_UP:  
  161.             yCaret = max(yCaret-1, 0);  
  162.             break;  
  163.   
  164.         case VK_DOWN:  
  165.             yCaret = min(yCaret+1, cyBuffer-1);  
  166.             break;  
  167.   
  168.         case VK_DELETE:  
  169.             for (x = xCaret; x < cxBuffer-1; x++)  
  170.                 BUFFER(x, yCaret) = BUFFER(x+1, yCaret);  
  171.             BUFFER(cxBuffer-1, yCaret) = ' ';  
  172.   
  173.             HideCaret(hwnd);  
  174.   
  175.             hdc = GetDC(hwnd);  
  176.   
  177.             SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));  
  178.   
  179.             TextOut(hdc, xCaret*cxChar, yCaret*cyChar, &BUFFER(xCaret, yCaret), cxBuffer-xCaret);  
  180.   
  181.             DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));  
  182.             ReleaseDC(hwnd, hdc);  
  183.             ShowCaret(hwnd);  
  184.             break;  
  185.         }  
  186.         SetCaretPos(xCaret*cxChar, yCaret*cyChar);  
  187.         return 0;  
  188.   
  189.     case WM_CHAR:  
  190.         for (i = 0; i < (int)LOWORD(lParam); i++)  
  191.         {  
  192.             switch (wParam)  
  193.             {  
  194.             case '\b':          // backspace  
  195.                 if (xCaret > 0)  
  196.                 {  
  197.                     xCaret--;  
  198.                     SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1);  
  199.                 }  
  200.                 break;  
  201.   
  202.             case '\t':          // tab  
  203.                 do  
  204.                 {  
  205.                     SendMessage(hwnd, WM_CHAR, ' ', 1);  
  206.                 }  
  207.                 while (xCaret % 8 != 0);  
  208.                 break;  
  209.   
  210.             case '\n':          // line feed  
  211.                 if (++yCaret == cyBuffer)  
  212.                     yCaret = 0;  
  213.                 break;  
  214.   
  215.             case '\r':          // carriage return  
  216.                 xCaret = 0;  
  217.                 if (++yCaret == cyBuffer)  
  218.                     yCaret = 0;  
  219.                 break;  
  220.   
  221.             case '\x1B':        // escape  
  222.                 for (y = 0; y < cyBuffer; y++)  
  223.                     for (x = 0; x < cxBuffer; x++)  
  224.                         BUFFER(x, y) = ' ';  
  225.   
  226.                 xCaret = 0;  
  227.                 yCaret = 0;  
  228.   
  229.                 InvalidateRect(hwnd, NULL, FALSE);  
  230.                 break;  
  231.   
  232.             default:            // character codes  
  233.                 BUFFER(xCaret, yCaret) = (TCHAR)wParam;  
  234.   
  235.                 HideCaret(hwnd);  
  236.                 hdc = GetDC(hwnd);  
  237.                 SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));  
  238.   
  239.                 TextOut(hdc, xCaret*cxChar, yCaret*cyChar, &BUFFER(xCaret, yCaret), 1);  
  240.   
  241.                 DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));  
  242.                 ReleaseDC(hwnd, hdc);  
  243.                 ShowCaret(hwnd);  
  244.   
  245.                 if (++xCaret == cxBuffer)  
  246.                 {  
  247.                     xCaret = 0;  
  248.                     if (++yCaret == cyBuffer)  
  249.                         yCaret = 0;  
  250.                 }  
  251.                 break;  
  252.             }  
  253.         }  
  254.   
  255.         SetCaretPos(xCaret*cxChar, yCaret*cyChar);  
  256.         return 0;  
  257.   
  258.     case WM_PAINT:  
  259.         hdc = BeginPaint(hwnd, &ps);  
  260.   
  261.         SelectObject(hdc, CreateFont(0, 0, 0, 0, 0, 0, 0, 0, dwCharSet, 0, 0, 0, FIXED_PITCH, NULL));  
  262.           
  263.         for (y = 0; y < cyBuffer; y++)  
  264.             TextOut(hdc, 0, y*cyChar, &BUFFER(0, y), cxBuffer);  
  265.   
  266.         DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));  
  267.   
  268.         EndPaint(hwnd, &ps);  
  269.         return 0;  
  270.   
  271.     case WM_DESTROY:  
  272.         PostQuitMessage(0);  
  273.         return 0;  
  274.     }  
  275.   
  276.     return DefWindowProc(hwnd, message, wParam, lParam);  
  277. }  



版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值