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

以下内容主要来自《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. switch (message)
  13. {
  14. case WM_CREATE:
  15. hdc = GetDC(hwnd);
  16. GetTextMetrics(hdc, &tm);       // 获取系统默认字体的尺寸
  17. cxChar = tm.tmAveCharWidth;
  18. // tmPitchAndFamily为1表示变宽字体,为0表示等宽字体
  19. cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
  20. cyChar = tm.tmHeight + tm.tmExternalLeading;
  21. ReleaseDC(hwnd, hdc);
  22. iMaxWidth = 40*cxChar + 22*cxCaps;
  23. return 0;
  24. case WM_SIZE:
  25. cxClient = LOWORD(lParam);
  26. cyClient = HIWORD(lParam);
  27. si.cbSize   = sizeof(si);
  28. si.fMask    = SIF_RANGE | SIF_PAGE;
  29. si.nMin     = 0;
  30. si.nMax     = NUMLINES-1;
  31. si.nPage    = cyClient / cyChar;
  32. SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
  33. si.cbSize   = sizeof(si);
  34. si.fMask    = SIF_RANGE | SIF_PAGE;
  35. si.nMin     = 0;
  36. si.nMax     = 2 + iMaxWidth/cxChar;
  37. si.nPage    = cxClient / cxChar;
  38. SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
  39. return 0;
  40. case WM_VSCROLL:
  41. si.cbSize   = sizeof(si);
  42. si.fMask    = SIF_ALL;
  43. GetScrollInfo(hwnd, SB_VERT, &si);
  44. iVertPos = si.nPos;
  45. switch (LOWORD(wParam))
  46. {
  47. case SB_TOP:
  48. si.nPos = si.nMin;
  49. break;
  50. case SB_BOTTOM:
  51. si.nPos = si.nMax;
  52. break;
  53. case SB_LINEUP:
  54. si.nPos -= 1;
  55. break;
  56. case SB_LINEDOWN:
  57. si.nPos += 1;
  58. break;
  59. case SB_PAGEUP:
  60. si.nPos -= si.nPage;
  61. break;
  62. case SB_PAGEDOWN:
  63. si.nPos += si.nPage;
  64. break;
  65. case SB_THUMBTRACK:
  66. si.nPos = si.nTrackPos;
  67. break;
  68. default:
  69. break;
  70. }
  71. si.fMask = SIF_POS;
  72. SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
  73. GetScrollInfo(hwnd, SB_VERT, &si);
  74. if (si.nPos != iVertPos)
  75. {
  76. ScrollWindow(hwnd, 0, cyChar*(iVertPos-si.nPos), NULL, NULL);
  77. UpdateWindow(hwnd);
  78. }
  79. return 0;
  80. case WM_HSCROLL:
  81. si.cbSize   = sizeof(si);
  82. si.fMask    = SIF_ALL;
  83. GetScrollInfo(hwnd, SB_HORZ, &si);
  84. iHorzPos = si.nPos;
  85. switch (LOWORD(wParam))
  86. {
  87. case SB_LINELEFT:
  88. si.nPos -= 1;
  89. break;
  90. case SB_LINERIGHT:
  91. si.nPos += 1;
  92. break;
  93. case SB_PAGELEFT:
  94. si.nPos -= si.nPage;
  95. break;
  96. case SB_PAGERIGHT:
  97. si.nPos += si.nPage;
  98. break;
  99. case SB_THUMBPOSITION:
  100. si.nPos = si.nTrackPos;
  101. break;
  102. default:
  103. break;
  104. }
  105. si.fMask = SIF_POS;
  106. SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
  107. GetScrollInfo(hwnd, SB_HORZ, &si);
  108. if (si.nPos != iHorzPos)
  109. {
  110. ScrollWindow(hwnd, cxChar*(iHorzPos-si.nPos), 0, NULL, NULL);
  111. UpdateWindow(hwnd);
  112. }
  113. return 0;
  114. case WM_KEYDOWN:
  115. switch (wParam)
  116. {
  117. case VK_HOME:
  118. SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);
  119. break;
  120. case VK_END:
  121. SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
  122. break;
  123. case VK_PRIOR:
  124. SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
  125. break;
  126. case VK_NEXT:
  127. SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
  128. break;
  129. case VK_UP:
  130. SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
  131. break;
  132. case VK_DOWN:
  133. SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
  134. break;
  135. case VK_LEFT:
  136. SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0);
  137. break;
  138. case VK_RIGHT:
  139. SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0);
  140. break;
  141. }
  142. return 0;
  143. case WM_PAINT:
  144. hdc = BeginPaint(hwnd, &ps);
  145. si.cbSize = sizeof(si);
  146. si.fMask = SIF_POS;
  147. GetScrollInfo(hwnd, SB_VERT, &si);
  148. iVertPos = si.nPos;
  149. GetScrollInfo(hwnd, SB_HORZ, &si);
  150. iHorzPos = si.nPos;
  151. iPaintBeg = max(0, iVertPos + ps.rcPaint.top/cyChar);
  152. iPaintEnd = min(NUMLINES-1, iVertPos + ps.rcPaint.bottom/cyChar);
  153. for (i = iPaintBeg; i <= iPaintEnd; i++)
  154. {
  155. x = cxChar * (1-iHorzPos);
  156. y = cyChar * (i-iVertPos);
  157. TextOut(hdc, x, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));
  158. TextOut(hdc, x + 22*cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));
  159. SetTextAlign(hdc, TA_RIGHT | TA_TOP);
  160. TextOut(hdc, x + 22*cxCaps + 40*cxChar, y, szBuffer, wsprintf(szBuffer, TEXT("%5d"),
  161. GetSystemMetrics(sysmetrics[i].iIndex)));
  162. // 将对齐方式设回正常方式
  163. SetTextAlign(hdc, TA_LEFT | TA_TOP);
  164. }
  165. EndPaint(hwnd, &ps);
  166. return 0;
  167. case WM_DESTROY:
  168. PostQuitMessage(0);
  169. return 0;
  170. }
  171. return DefWindowProc(hwnd, message, wParam, lParam);
  172. }

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

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

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

 
http://blog.csdn.net/guzhou_diaoke/article/details/8170366

Win32 键盘事件 - 击键消息、字符消息、插入符号(光标)的更多相关文章

  1. JS键盘事件之键控Div

    自上次做的鼠标拖动Div之后,看到fgm.cc的例子,发现用键盘操控Div貌似也是十分有趣,这些DOM操作随着jquery的没落,虽然渐渐少用了,不过有些DOM操作还是必不可少的.现在是虽然数据为王( ...

  2. OSX 鼠标和键盘事件

    本文转自:http://www.macdev.io/ebook/event.html 事件分发过程 OSX 与用户交互的主要外设是鼠标,键盘.鼠标键盘的活动会产生底层系统事件.这个事件首先传递到IOK ...

  3. 键盘事件keydown、keypress、keyup随笔整理总结(摘抄)

    原文1:http://www.cnblogs.com/silence516/archive/2013/01/25/2876611.html 原文2:http://www.cnblogs.com/leo ...

  4. 详解键盘事件(keydown,keypress,keyup)

    一.键盘事件基础 1.定义 keydown:按下键盘键 keypress:紧接着keydown事件触发(只有按下字符键时触发) keyup:释放键盘键 顺序为:keydown -> keypre ...

  5. 键盘事件keydown、keypress、keyup随笔整理总结

    英文输入法:   事件触发顺序:keydown - > keypress - > keyup   中文输入法:   firfox:输入触发keydown,回车确认输入触发keyup chr ...

  6. 键盘事件keydown、keypress、keyup

    事件触发顺序:keydown - > keypress - > keyup   中文输入法:   firfox:输入触发keydown,回车确认输入触发keyup chrome:输入触发k ...

  7. .net MVC 微信公众号 点击菜单拉取消息时的事件推送

    官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141016&token=&lang=zh_CN ...

  8. C# 键盘响应事件及键值对照表

    键盘响应事件总结 键盘响应事件是在用户按下某个键后触发的事件,可以是任意操作,但不是任意键都可以被捕获的. 原型:public event KeyPressEventHandler KeyPress ...

  9. Win32汇编学习(7):鼠标输入消息

    这次我们将学习如何在我们的窗口过程函数中处理鼠标按键消息.例子演示了如何等待鼠标左键按下消息,我们将在按下的位置显示一个字符串. 理论: 和处理键盘输入一样,WINDOWS将捕捉鼠标动作并把它们发送到 ...

随机推荐

  1. [Ramda] Handle Branching Logic with Ramda's Conditional Functions

    When you want to build your logic with small, composable functions you need a functional way to hand ...

  2. 【2016 Summary】为过往补课、为将来夯实

    前言 看了CSDN上非常多"我的2016"年终总结,也就不能免俗地来写一波.按着时间轴捋一捋这过去一年的经过,也算是这元旦假期总一个午后的休闲时光了.(结果没想到的是午饭前開始写的 ...

  3. 1. java.util.concurrent - Java 并发工具包

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  4. ios开发事件处理之 四:hittest方法的底层实现与应用

    #import "XMGWindow.h" /** 1:注意点:hitTest方法内部会调用pointInside方法,询问触摸点是否在自己身上,当遍历子控件时,传入的坐标点要进行 ...

  5. 【39.29%】【codeforces 552E】Vanya and Brackets

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  6. 如何查看Outlook邮件的源码(包括ip)

    如何查看Outlook邮件的源码(包括ip) 一.总结 1.右键点击邮件可出现 view message details. 二.如何查看Outlook邮件的源码(包括ip) 1.点收件箱 2.鼠标右键 ...

  7. Android 设置图片 Bitmap任意透明度

    两种思路,第一种思路是通过对Bitmap进行操作,将Bitmap的像素值get到一个int[]数组里,因为在android里Bitmap通常是ARGB8888格式,所以最高位就是A通道的值,对齐进行改 ...

  8. 三种方式使得iOS应用能够在后台进行数据更新和下载

    三种方式使得iOS程序即使在关闭或崩溃的情况下也能够在后台持续进行一些任务,比如更新程序界面快照,下载文件等.这三个方法分别是 Background Fetch,Remote Notification ...

  9. 【codeforces 776D】The Door Problem

    [题目链接]:http://codeforces.com/contest/776/problem/D [题意] 每个门严格由两个开关控制; 按一下开关,这个开关所控制的门都会改变状态; 问你能不能使所 ...

  10. Vue中this的绑定

    之前写过一篇文章 ES6与React中this完全解惑 其实Vue也是相同的道理.在Vue的官方文档中提到: 不要在选项属性或回调上使用箭头函数,比如 created: () => consol ...