一切的起因就是Silverlight对F10键根本没有响应。在按F10键时,根本不会触发KeyDown事件。
Silverlight5之前的版本我不太清楚,不过Silverlight5新特性中有使用P/Invoke调用非托管代码。既然这样,做个键盘钩子不就解决了?我喜欢DllImport。
正文
先了解钩子相关的信息(SetWindowsHookEx、UnhookWindowsHookEx),下面是原生代码。
int nCode, Int32 wParam, IntPtr lParam);
2:
, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
int threadId);
5:
, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
int idHook);
8:
, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
int nCode, Int32 wParam, IntPtr lParam);
11:
, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
string lpModuleName);
其中委托HookProc用于设置钩子的回调函数。
处理回调的时候还会用到键盘钩子的封送结构。
1: [StructLayout(LayoutKind.Sequential)]
class KeyboardHookStruct
3: {
//表示一个在1到254间的虚似键盘码
int scanCode;
int flags;
int time;
int dwExtraInfo;
9: }
以下为主体代码。
//常量
//低级键盘钩子
int WM_KEYDOWN = 0x100;
int WM_SYSKEYDOWN = 0x104;
5:
//钩子句柄
7: HookProc HookProcDelegate;
8:
//回调函数
10: [AllowReversePInvokeCalls]
int nCode, Int32 wParam, IntPtr lParam)
12: {
//可以增加当前窗口是否是活动窗口的判断,不然低级键盘钩子还会截获所有的键盘消息
//可以使用App.Current.MainWindow.IsActive
new KeyboardHookStruct();
16: Marshal.PtrToStructure(lParam, khs);
//KeyDown
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
19: {
//F10
21: {
//Do something
23: }
24: }
return CallNextHookEx(iKeyboardHook, nCode, wParam, lParam);
26: }
27:
/// <summary>
/// 注册键盘钩子
/// </summary>
void Hook()
32: {
33: IntPtr ip = GetModuleHandle(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].Name);
new HookProc(HookProcHandler);
35: iKeyboardHook = SetWindowsHookEx(13, HookProcDelegate, ip, 0);
if (iKeyboardHook == 0)
37: {
);
39: }
40: }
41:
/// <summary>
/// 卸载键盘钩子
/// </summary>
void UnHook()
46: {
if (!UnhookWindowsHookEx(iKeyboardHook))
48: {
);
50: }
51: iKeyboardHook = 0;
52: }
回调函数的AllowReversePInvokeCalls属性允许非托管方法调用托管方法。
结语
现在截获F10就是小意思了。还可以根据这些封装一下,不过暂时不需要就先这样了。
Tips:
1. 注册钩子时SetWindowsHookEx函数的threadId参数设置为0,所以需要在回调函数里判断当前Silverlight窗体是否为活动窗体。
2. KeyboardHookStruct.vkCode对应的键值是System.Windows.Forms命名空间里Keys枚举的键值,所以判断是否是F10键时用的是0x79,而不是System.Windows.Input命名空间里Key枚举的65。