📄 见招拆招windows程序设计(五).txt
字号:
内容代码
右按键时,假如同时压下ALT键,那么内容代码为1。对WM_SYSKEYUP与WM_SYSKEYDOWN而言,此位总视为1;而对WM_SYSKEYUP与WM_KEYDOW消息而言,此位为0。除了两个之外:
如果活动窗口最小化了,则它没有输入焦点。这时候所有的按键都会产生WM_SYSKEYUP和WM_SYSKEYDOWN消息。如果Alt键未被按下,则内容代码字段被设定为0。Windows使用WM_SYSKEYUP和WM_SYSKEYDOWN消息,从而使最小化了的活动窗口不处理这些按键。
对于一些外国语文(非英文)键盘,有些字符是通过Shift、Ctrl或者Alt键与其它键相组合而产生的。这时内容代码为1,但是此消息并非系统按键消息。
键的先前状态
如果在此之前键是释放的,则键的先前状态为0,否则为1。对WM_KEYUP或者WM_SYSKEYUP消息,它总是设定为1;但是对WM_KEYDOWN或者WM_SYSKEYDOWN消息,此位可以为0,也可以为1。如果为1,则表示该键是自动重复功能所产生的第二个或者后续消息。
转换状态
如果键正被按下,则转换状态为0;如果键正被释放,则转换状态为1。对WM_KEYDOWN或者WM_SYSKEYDOWN消息,此字段为0;对WM_KEYUP或者WM_SYSKEYUP消息,此字段为1。
位移状态
在处理按键消息时,您可能需要知道是否按下了位移键(Shift、Ctrl和Alt)或开关键(Caps Lock、Num Lock和Scroll Lock)。通过调用GetKeyState函数,您就能获得此信息。例如:
iState = GetKeyState (VK_SHIFT) ;
如果按下了Shift,则iState值为负(即设定了最高位置位)。如果Caps Lock键打开,则从
iState = GetKeyState (VK_CAPITAL) ;
传回的值低位被设为1。此位与键盘上的小灯保持一致。
通常,您在使用GetKeyState时,会带有虚拟键码VK_SHIFT、VK_CONTROL和VK_MENU(在说明Alt键时呼叫)。使用GetKeyState时,您也可以用下面的标识符来确定按下的Shift、Ctrl或Alt键是左边的还是右边的:VK_LSHIFT、VK_RSHIFT、VK_LCONTROL、VK_RCONTROL、VK_LMENU、VK_RMENU。这些标识符只用于GetKeyState和GetAsyncKeyState(下面将详细说明)。
使用虚拟键码VK_LBUTTON、VK_RBUTTON和VK_MBUTTON,您也可以获得鼠标键的状态。不过,大多数需要监视鼠标键与按键相组合的Windows应用程序都使用其它方法来做到这一点-即在接收到鼠标消息时检查按键。实际上,位移状态信息包含在鼠标信息中。
请注意GetKeyState的使用,它并非实时检查键盘状态,而只是检查直到目前为止正在处理的消息的键盘状态。多数情况下,这正符合您的要求。如果您需要确定使用者是否按下了Shift-Tab,请在处理Tab键的WM_KEYDOWN消息时呼叫GetKeyState,带有参数VK_SHIFT。如果GetKeyState传回的值为负,那么您就知道在按下Tab键之前按下了Shift键。并且,如果在您开始处理Tab键之前,已经释放了Shift键也没有关系。您知道,在按下Tab键的时候Shift键是按下的。
GetKeyState不会让您获得独立于普通键盘消息的键盘信息。例如,您或许想暂停窗口消息处理程序的处理,直到您按下F1功能键为止:
while (GetKeyState (VK_F1) >= 0) ; // WRONG !!!
不要这么做!这将让程序当死(除非在执行此叙述之前早就从消息队列中接收到了F1的WM_KEYDOWN)。如果您确实需要知道目前某键的状态,那么您可以使用GetAsyncKeyState。
使用按键消息
如果程序能够获得每个按键的信息,这当然很理想,但是大多数Windows程序忽略了几乎所有的按键,而只处理部分的按键消息。WM_SYSKEYDOWN和WM_SYSKEYUP消息是由Windows系统函数使用的,您不必为此费心,就算您要处理WM_KEYDOWN消息,通常也可以忽略WM_KEYUP消息。
Windows程序通常为不产生字符的按键使用WM_KEYDOWN消息。虽然您可能认为借助按键消息和位移键状态信息能将按键消息转换为字符消息,但是不要这么做,因为您将遇到国际键盘间的差异所带来的问题。例如,如果您得到wParam等于0x33的WM_KEYDOWN消息,您就可以知道使用者按下了键3,到此为止一切正常。这时,如果用GetKeyState发现Shift键被按下,您就可能会认为使用者输入了#号,这可不一定。比如英国使用者就是在输入£。
对于光标移动键、功能键、Insert和Delete键,WM_KEYDOWN消息是最有用的。不过, Insert、Delete和功能键经常作为菜单快捷键。因为Windows能把菜单快捷键翻译为菜单命令消息,所以您就不必自己来处理按键。
在Windows之前的MS-DOS应用程序中大量使用功能键与Shift、Ctrl和Alt键的组合,同样地,您也可以在Windows程序中使用(实际上,Microsoft Word将大量的功能键用作命令快捷方式),但并不推荐这样做。如果您确实希望使用功能键,那么这些键应该是重复菜单命令。Windows的目标之一就是提供不需要记忆或者使用复杂命令流程的使用者接口。
因此,可以归纳如下:多数情况下,您将只为光标移动键(有时也为Insert和Delete键)处理WM_KEYDOWN消息。在使用这些键的时候,您可以通过GetKeyState来检查Shift键和Ctrl键的状态。例如,Windows程序经常使用Shift与光标键的组合键来扩大文书处理里选中的范围。Ctrl键常用于修改光标键的意义。例如,Ctrl与右箭头键相组合可以表示光标右移一个字。
决定您的程序中使用键盘方式的最佳方法之一是了解现有的Windows程序使用键盘的方式。如果您不喜欢那些定义,当然可以对其加以修改,但是这样做不利于其它人很快地学会使用您的程序。
为SYSMETS加上键盘处理功能
在编写前面三个版本的SYSMETS程序时,我们还不了解键盘,只能使用滚动条和鼠标来卷动文字。现在我们知道了处理键盘消息的方法,那么不妨在程序中加入键盘接口。显然,这是处理光标移动键的工作。我们将大多数光标键(Home、End、Page Up、Page Down、Up Arrow和Down Arrow)用于垂直卷动,左箭头键和右箭头键用于不太重要的水平卷动。
建立键盘接口的一种简单方法是在窗口消息处理程序中加入与WM_VSCROLL和WM_HSCROLL处理方式相仿,而且本质上相同的WM_KEYDOWN处理方法。不过这样子做是不聪明的,因为如果要修改滚动条的做法,就必须相对应地修改WM_KEYDOWN。
为什么不简单地将每一种WM_KEYDOWN消息都翻译成同等效用的WM_VSCROLL或者WM_HSCROLL消息呢?通过向窗口消息处理程序发送假冒消息,我们可能会让WndProc认为它获得了卷动信息。
在Windows中,这种方法是可行的。发送消息的函数叫做SendMessage,它所用的参数与传递到窗口消息处理程序的参数是相同的:
SendMessage (hwnd, message, wParam, lParam) ;
在呼叫SendMessage时,Windows呼叫窗口句柄为hwnd的窗口消息处理程序,并把这四个参数传给它。当窗口消息处理程序完成消息处理之后,Windows把控制传回到SendMessage呼叫之后的下一道叙述。您发送消息过去的窗口消息处理程序,可以是同一个窗口消息处理程序、同一程序中的其它窗口消息处理程序或者其它应用程序,中的窗口消息处理程序。
下面说明在SYSMETS程序中使用SendMessage处理WM_KEYDOWN代码的方法:
caseWM_KEYDOWN:
switch (wParam)
{
case VK_HOME:
SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0) ;
break ;
case VK_END:
SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0) ;
break ;
case VK_PRIOR:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0) ;
break ;
至此,您已经有了大概观念了吧。我们的目标是为滚动条添加键盘接口,并且也正在这么做。通过把卷动消息发送到窗口消息处理程序,我们实作了用光标移动键进行卷动列的功能。现在您知道在SYSMETS3中为WM_VSCROLL消息加上SB_TOP和SB_BOTTOM处理码的原因了吧。在那里并没有用到它,但是现在处理Home和End键时就有用了。如程序6-1所示的SYSENTS4就加上了这些变化。
程序6-1 SYSMETS4
SYSMETS4.ASM
;MASMPlus 代码模板 - 普通的 Windows 程序代码
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include winmm.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib winmm.lib
include macro.asm
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
NUMLINES equ (sysmetricsEnd - sysmetrics) / 4 /3
.DATA
szAppName db "SysMets4",0
szShow01 db "SM_CXSCREEN",0
szShow02 db "Screen width in pixels",0
szShow03 db "SM_CYSCREEN",0
szShow04 db "Screen height in pixels",0
szShow05 db "SM_CXVSCROLL",0
szShow06 db "Vertical scroll width",0
szShow07 db "SM_CYHSCROLL",0
szShow08 db "Horizontal scroll height",0
szShow09 db "SM_CYCAPTION",0
szShow10 db "Caption bar height",0
szShow11 db "SM_CXBORDER",0
szShow12 db "Window border width",0
szShow13 db "SM_CYBORDER",0
szShow14 db "Window border height",0
szShow15 db "SM_CXFIXEDFRAME",0
szShow16 db "Dialog window frame width",0
szShow17 db "SM_CYFIXEDFRAME",0
szShow18 db "Dialog window frame height",0
szShow19 db "SM_CYVTHUMB",0
szShow20 db "Vertical scroll thumb height",0
szShow21 db "SM_CXHTHUMB",0
szShow22 db "Horizontal scroll thumb width",0
szShow23 db "SM_CXICON",0
szShow24 db "Icon width",0
szShow25 db "SM_CYICON",0
szShow26 db "Icon height",0
szShow27 db "SM_CXCURSOR",0
szShow28 db "Cursor width",0
szShow29 db "SM_CYCURSOR",0
szShow30 db "Cursor height",0
szShow31 db "SM_CYMENU",0
szShow32 db "Menu bar height",0
szShow33 db "SM_CXFULLSCREEN",0
szShow34 db "Full screen client area width",0
szShow35 db "SM_CYFULLSCREEN",0
szShow36 db "Full screen client area height",0
szShow37 db "SM_CYKANJIWINDOW",0
szShow38 db "Kanji window height",0
szShow39 db "SM_MOUSEPRESENT",0
szShow40 db "Mouse present flag",0
szShow41 db "SM_CYVSCROLL",0
szShow42 db "Vertical scroll arrow height",0
szShow43 db "SM_CXHSCROLL",0
szShow44 db "Horizontal scroll arrow width",0
szShow45 db "SM_DEBUG",0
szShow46 db "Debug version flag",0
szShow47 db "SM_SWAPBUTTON",0
szShow48 db "Mouse buttons swapped flag",0
szShow49 db "SM_CXMIN",0
szShow50 db "Minimum window width",0
szShow51 db "SM_CYMIN",0
szShow52 db "Minimum window height",0
szShow53 db "SM_CXSIZE",0
szShow54 db "Min/Max/Close button width",0
szShow55 db "SM_CYSIZE",0
szShow56 db "Min/Max/Close button height",0
szShow57 db "SM_CXSIZEFRAME",0
szShow58 db "Window sizing frame width",0
szShow59 db "SM_CYSIZEFRAME",0
szShow60 db "Window sizing frame height",0
szShow61 db "SM_CXMINTRACK",0
szShow62 db "Minimum window tracking width",0
szShow63 db "SM_CYMINTRACK",0
szShow64 db "Minimum window tracking height",0
szShow65 db "SM_CXDOUBLECLK",0
szShow66 db "Double click x tolerance",0
szShow67 db "SM_CYDOUBLECLK",0
szShow68 db "Double click y tolerance",0
szShow69 db "SM_CXICONSPACING",0
szShow70 db "Horizontal icon spacing",0
szShow71 db "SM_CYICONSPACING",0
szShow72 db "Vertical icon spacing",0
szShow73 db "SM_MENUDROPALIGNMENT",0
szShow74 db "Left or right menu drop",0
szShow75 db "SM_PENWINDOWS",0
szShow76 db "Pen extensions installed",0
szShow77 db "SM_DBCSENABLED",0
szShow78 db "Double-Byte Char Set enabled",0
szShow79 db "SM_CMOUSEBUTTONS",0
szShow80 db "Number of mouse buttons",0
szShow81 db "SM_SECURE",0
szShow82 db "Security present flag",0
szShow83 db "SM_CXEDGE",0
szShow84 db "3-D border width",0
szShow85 db "SM_CYEDGE",0
szShow86 db "3-D border height",0
szShow87 db "SM_CXMINSPACING",0
szShow88 db "Minimized window spacing width",0
szShow89 db "SM_CYMINSPACING",0
szShow90 db "Minimized window spacing height",0
szShow91 db "SM_CXSMICON",0
szShow92 db "Small icon width",0
szShow93 db "SM_CYSMICON",0
szShow94 db "Small icon height",0
szShow95 db "SM_CYSMCAPTION",0
szShow96 db "Small caption height",0
szShow97 db "SM_CXSMSIZE",0
szShow98 db "Small caption button width",0
szShow99 db "SM_CYSMSIZE",0
szShow100 db "Small caption button height",0
szShow101 db "SM_CXMENUSIZE",0
szShow102 db "Menu bar button width",0
szShow103 db "SM_CYMENUSIZE",0
szShow104 db "Menu bar button height",0
szShow105 db "SM_ARRANGE",0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -