接下来,我在测试工程的窗体上放置了一个ListBox控件做一个对比,其实ToolBox和ListBox在界面表现上有相似之处,就是都有子Item,并且在ListBox上点击Down是起作用的,ListBox并没有失去焦点,这说明这时Up,Down按键没有成为导航键。我想Windows一定是对默认的导航键Up,Down,Left,Right有默认的处理,除非你希望你的控件希望自己处理这些键。用反汇编工具看了一下ListBoxControl控件的源代码,发现一个有趣的函数:
在这里面,ListBoxControl允许Prior,Next,End,Home成为有效的输入键,接着一路跟下去,看看WinForm控件的基类Control的这个函数是如何处理的:
注意这一行return ((((int) this.SendMessage(0x87, 0, 0)) & num) != 0);0x87是什么windows消息呢,打开WinUser.h文件,发现是WM_GETDLGCODE,在MSDN中的描述是这样的:
The WM_GETDLGCODE message is sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.
也就是说windows用这个消息来判断哪些类型的输入交给控件本身来处理。然后,我注意到,对于方向导航键,函数都给于一个值5与this.SendMessage(0x87, 0, 0))的返回值进行与操作,那么this.SendMessage(0x87, 0, 0))的返回值都可能是什么值呢,WinUser.h中是这样声明的:
从这段代码里和控件实际的行为我们可以得出一个结论,那就是,控件本身是不处理方向键和Tab键的,因为他们有默认的行为,也就是支持焦点在窗体的控件之间转换。如果你想要处理这些导航键,那么结论很简单,就是重载IsInputKey方法,它是一个保护类型的虚方法。
在ToolBox控件的代码里重载IsinputKey方法:
当用户点击的键是Up,Down的时候,返回true,这时我们的OnKeyDown方法里就可以捕获到Up,Down的点击事件了。