Chapter 6 The keyboard

来源:互联网 发布:hadoop书籍推荐 知乎 编辑:程序博客网 时间:2024/06/09 14:10

Keyboard Basic:

键盘输入对于系统功能的Keystroke会忽视掉,就是那些ALT+??,Windows会把keystroke effect通知给程序;

对于菜单快捷键:Ctrl+??之类的也会忽视掉,因为Windows会把这些交给DefWindowProc处理转化成菜单命令项被选中的消息。

焦点:

The window that receives a particular keyboard event is the window that has the input focus.

有input focus的要么是active window要么是active window的子窗口,active window一般是边界被高亮。

用户按键与释放键,Windows和Keyboard的驱动程序就会把扫描码转化为格式化码并存入system message queue而不是应用程序的消息队列,当应用程序处理完前一个用户输入消息之后,Windows才会把后一批message放到应用程序的消息队列中。

如果不那样做,当出现用户输入比程序处理还快的情况出现时,如果一有用户输入就放到应用程序的消息队列里面,当遇到一些特殊输入会转变active window的时候,还没处理到这个转变消息,后续的输入都输入到现在的active window消息队列中,而这些后续的用户输入应该放到转变的active window消息队列才对。

对于能产生可见字符的keystroke combinations,Windows会发送2个keystroke message和character message
对于不能产生可见字符,例如shift,功能键,Delete等,Windows只会发送keystroke message

 

Keystroke Message:

当你按下一个键的时候,Windows就会把一个WM_KEYDOWN或者是WM_SYSKEYDOWN放到拥有focus的active windows的消息队列里,准确点讲应该是先放到system message queue里,再放到对应的应用程序消息队列里吧。

系统击键:

Alt的组合键产生的是WM_SYSKEYUP和WM_SYSKEYDOWN,一般应用程序应该像之前讲的那样忽视这些击键,交给DefWindowProc处理就行,例如:ALT+F4,交给DefWindowProc处理应该能得到一个WM_DESTROY消息。

不与Alt组合的话产生的就是WM_KEYDOWN和WM_KEYUP了,应用程序可以根据需要是否对这些击键做出反应。而且WM_KEYDOWN,WM_KEYUP消息中wparam参数是virtual key code,能知道你按下的或者释放的而是什么键。

Virtual Key codes:

 

 

就是根据这些虚拟键码来判定你操作的是什么键了。

WM_SYSKEYUP,WM_SYSKEYDOWN,WM_KEYUP,WM_KEYDOWN4个消息wparam包含了所击键的虚拟码,而lparam参数则包含帮组理解击键的其他信息.

lparam参数:

Repeat Count:当你按住一个键不松手,输入速率比起过程函数处理还要快的时候就会把一系列WM_KEYDOWN合并成一个,Repeat Count则记录输入了几个WM_KEYDOWN消息了。

OEM Scan Code:扫描码是以前老一代程序员用的了,现在就暂时无视就行。

Extended Key Flag:当你按的键是加强型键盘多出来的一些功能键的时候,该位为1,否则为0。

Context Code:击键的同时按了Alt,该位就为1,否则为0。

Previous Key State:如果键之前处于释放状态该位为0,之前处于按下的状态,该位为1。

Transition State:键正被按下该位为0,正被释放该位为1,也就是WM_KEYDOWN,WM_SYSKEYDOWN该位是0,WM_KEYUP和WM_SYSKEYUP该位为1

 

Shift State:

击键的时候你需要看下Shift,Ctrl,Alt之类转义键位是否被按下:

iState = GetKeyState (VK_SHIFT) ;
The iState variable will be negative (that is, the high bit is set) if the Shift key is down.

iState = GetKeyState (VK_CAPITAL) ;
has the low bit set if the Caps Lock key is toggled on.

举个例子:

If you need to determine if the user typed Shift-Tab, you can call GetKeyState with the VK_SHIFT parameter while processing the WM_KEYDOWN message for the Tab key. If the return value of GetKeyState is negative, you know that the Shift key was pressed before the Tab key. And it doesn't matter if the Shift key has already been released
by the time you get around to processing the Tab key. You know that the Shift key was down when Tab was pressed.

 

Character Message:

如果WM_KEYDOWN消息是产生一个字符,那么消息循环中TranslateMessage(&msg);这个函数就会把WM_KEYDOWN后面放多一个WM_CHAR消息,这个消息的wparam参数不再是virtual key code了而是字符的ASCII或者Unicode编码,而lparam参数就依然与产生WM_CHAR的WM_KEYDOWN消息的lparam参数一样。

例子:你按键盘A键:

消息队列里面是:WM_KEYDOWN(0x41 A的虚拟键码,但是没定义相应的宏)-->WM_CHAR(0x61 'a'的字符编码)-->WM_KEYUP(0x41 A的虚拟键码)

对于keystroke message和character message我们处理的一般规则是:如果要读取输入的字符,那么就处理WM_CHAR;如果要处理功能键,光标键,Delete键,Insert键,Shift,Ctrl,Alt这些就处理WM_KEYDOWN

对于Tab,Space,Enter这些既是字符,同时又有virtual key code的键,要看你自己决定了,作者本身倾向于放在WM_CHAR里面处理。

Dead-Character是那些非美标键盘的,例如德国键盘有的字符有音调,按+/=键的时候可以产生WM_DEADCHAR,其wparam参数是这个音调的ASCII或者Unicode编码,接着按a键,就会产生一个带音调的WM_CHAR,其wparam参数是以带音调的'a'的编码,所以说Windows才会忽视WM_DEADCHAR,因为WM_CHAR的wparam以带有音调。


Stock Font:

Windows提供了7种字体,可以通过GetStockObject来获取:
ANSI_FIXED_FONT      ANSI_VAR_FONT        SYSTEM_FONT         SYSTEM_FIXED_FONT        OEM_FIXED_FONT      DEVICE_DEFAULT_FONT       DEFAULT_GUI_FONT
字体中的字符集由于不同国家有不同的需要,所以即使是同样的编码,在非英语键盘的情况下打印出来的却不一定是你想要的那个字符,这部分由于没办法实操下,不是很懂,所以不深入,直接跳过了。

Caret:

CreateCaret(hwnd,hBitmap,iWidth,iHeight);//创建Caret
SetCaret(x,y);//设置Caret的位置
ShowCaret(hwnd);//显示Caret
HideCaret(hwnd);//隐藏Caret
DestroyCaret();//销毁Caret

一个消息队列就只支持一个Caret,如果你程序有多个窗口,而你在WM_CREATE里面CreateCaret,在WM_DESTROY里面DestroyCaret,那么凡是用这个过程函数创建起来的窗口全部都共享同一个Caret了,可以用一个实验来看下结果是怎样:在WinMain里面创建2个基于同一个窗口类的窗口,分别title为111和222吧,可以跟踪调试过程,看到先创建111窗口,它在WM_CREATE里创建了Caret,接着ShowWindow之后,就可以看得到111窗口出现了Caret,接着是222窗口的创建,222的ShowWindow结束之后,111窗口的Caret不见了,而222窗口出现Caret了,这就充分说明了Caret的共享性了,讲明白点就是多个窗口公用1个Caret,这样显然是不正确的,例如你在111里面写到第3行,222没写过东西,Caret在111里面闪在第3行,这时换222窗口作为active Window,由于共用Caret导致Caret在222里面出现在第3行而不是最上面那行,这样肯定不正确了。

那么解决这个办法就是:只在active Window才显示Caret,也只有这样做才有意义。不是正在被使用的窗口,闪着也没用吧,那么对于一个窗口它是不是active window呢,就要看WM_SETFOCUS这个消息了。思路是这样的:为每个窗口保存一个POINT吧,用来保存每个窗口的Caret的位置而不至于共享导致混乱,而Caret只在WM_SETFOCUS里面被创建,WM_KILLFOCUS里面被销毁,即是窗口被选中的时候,创建Caret,根据保存的POINT来SetCaretPos,而不被选中的时候就DestroyCaret。这样子就能各个窗口不会乱乱的了。

接着是一些Caret的注意事项:创建的Caret是隐藏的,必须ShowCaret才能见到,另外还有一点很重要的就是在非WM_PAINT绘制画面的时候一定要先HideCaret,画完之后再ShowCaret,否则会出现残影的效果,举个例子如果你的Caret比较宽,你按退格键,闪烁的Caret会向前移,但是后面很有可能拖着一个原来的黑色Caret,为了避免这种情况一定要先隐藏了Caret再画图,画图完了才Show。
0 0
原创粉丝点击