C# 构子的实现
来源:互联网 发布:linux 命令下载文件 sz 编辑:程序博客网 时间:2024/06/05 23:50
工具/原料
Visual Studio(本文使用VS2013,其他版本亦可)。
基础知识
使用钩子之前,需要使用SetWindowsHookEx()函数创建钩子,使用完毕之后要UnhookWindowsHookEx()函数卸载钩子,“钩”到消息后操作系统会自动调用在创建钩子时注册的回调函数来处理消息,处理完后调用CallNextHookEx()函数等待或处理下一条消息。有关钩子的详细信息请见参考--C#鼠标钩子,其中已介绍。
对于键盘钩子,钩子类型为WH_KEYBOARD_LL=13,只需要设置SetWindowsHookEx的idHook参数为13即可“钩”到键盘消息。关于钩子类型的资料见参考资料--钩子类型。
END
键盘钩子实例
启动VS,新建C# WinForm项目,命名为“Cs键盘钩子”,如下:
对主窗口布局,如下:
添加Win32Api引用,代码如下:
public class Win32Api
{
#region 常数和结构
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
public const int WH_KEYBOARD_LL = 13;
[StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型
public class KeyboardHookStruct
{
public int vkCode; //表示一个在1到254间的虚似键盘码
public int scanCode; //表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
#endregion
#region Api
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
//安装钩子的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
//卸下钩子的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
//下一个钩挂的函数
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
[DllImport("user32")]
public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32")]
public static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("kernel32.dll", CharSet = CharSet.Auto,CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
添加新建类KeyboardHook,封装键盘钩子,代码如下:
public class KeyboardHook
{
int hHook;
Win32Api.HookProc KeyboardHookDelegate;
public event KeyEventHandler OnKeyDownEvent;
public event KeyEventHandler OnKeyUpEvent;
public event KeyPressEventHandler OnKeyPressEvent;
public KeyboardHook() { }
public void SetHook()
{
KeyboardHookDelegate = new Win32Api.HookProc(KeyboardHookProc);
Process cProcess = Process.GetCurrentProcess();
ProcessModule cModule = cProcess.MainModule;
var mh = Win32Api.GetModuleHandle(cModule.ModuleName);
hHook = Win32Api.SetWindowsHookEx(Win32Api.WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);
}
public void UnHook()
{
Win32Api.UnhookWindowsHookEx(hHook);
}
private List<Keys> preKeysList = new List<Keys>();//存放被按下的控制键,用来生成具体的键
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
//如果该消息被丢弃(nCode<0)或者没有事件绑定处理程序则不会触发事件
if ((nCode >= 0) && (OnKeyDownEvent != null || OnKeyUpEvent != null || OnKeyPressEvent != null))
{
Win32Api.KeyboardHookStruct KeyDataFromHook = (Win32Api.KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.KeyboardHookStruct));
Keys keyData = (Keys)KeyDataFromHook.vkCode;
//按下控制键
if ((OnKeyDownEvent != null || OnKeyPressEvent != null) && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN))
{
if (IsCtrlAltShiftKeys(keyData) && preKeysList.IndexOf(keyData) == -1)
{
preKeysList.Add(keyData);
}
}
//WM_KEYDOWN和WM_SYSKEYDOWN消息,将会引发OnKeyDownEvent事件
if (OnKeyDownEvent != null && (wParam == Win32Api.WM_KEYDOWN || wParam == Win32Api.WM_SYSKEYDOWN))
{
KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData));
OnKeyDownEvent(this, e);
}
//WM_KEYDOWN消息将引发OnKeyPressEvent
if (OnKeyPressEvent != null && wParam == Win32Api.WM_KEYDOWN)
{
byte[] keyState = new byte[256];
Win32Api.GetKeyboardState(keyState);
byte[] inBuffer = new byte[2];
if (Win32Api.ToAscii(KeyDataFromHook.vkCode, KeyDataFromHook.scanCode, keyState, inBuffer, KeyDataFromHook.flags) == 1)
{
KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
OnKeyPressEvent(this, e);
}
}
//松开控制键
if ((OnKeyDownEvent != null || OnKeyPressEvent != null) && (wParam == Win32Api.WM_KEYUP || wParam == Win32Api.WM_SYSKEYUP))
{
if (IsCtrlAltShiftKeys(keyData))
{
for (int i = preKeysList.Count - 1; i >= 0; i--)
{
if (preKeysList[i] == keyData) { preKeysList.RemoveAt(i); }
}
}
}
//WM_KEYUP和WM_SYSKEYUP消息,将引发OnKeyUpEvent事件
if (OnKeyUpEvent != null && (wParam == Win32Api.WM_KEYUP || wParam == Win32Api.WM_SYSKEYUP))
{
KeyEventArgs e = new KeyEventArgs(GetDownKeys(keyData));
OnKeyUpEvent(this, e);
}
}
return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
}
//根据已经按下的控制键生成key
private Keys GetDownKeys(Keys key)
{
Keys rtnKey = Keys.None;
foreach (Keys i in preKeysList)
{
if (i == Keys.LControlKey || i == Keys.RControlKey) { rtnKey = rtnKey | Keys.Control; }
if (i == Keys.LMenu || i == Keys.RMenu) { rtnKey = rtnKey | Keys.Alt; }
if (i == Keys.LShiftKey || i == Keys.RShiftKey) { rtnKey = rtnKey | Keys.Shift; }
}
return rtnKey | key;
}
private Boolean IsCtrlAltShiftKeys(Keys key)
{
if (key == Keys.LControlKey || key == Keys.RControlKey || key == Keys.LMenu || key == Keys.RMenu || key == Keys.LShiftKey || key == Keys.RShiftKey) { return true; }
return false;
}
}
在主窗体中添加代码,如下:
public MainForm()
{
InitializeComponent();
}
KeyboardHook kh;
private void Form1_Load(object sender, EventArgs e)
{
kh = new KeyboardHook();
kh.SetHook();
kh.OnKeyDownEvent += kh_OnKeyDownEvent;
}
void kh_OnKeyDownEvent(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.S | Keys.Control)) { this.Show(); }//Ctrl+S显示窗口
if (e.KeyData == (Keys.H | Keys.Control)) { this.Hide(); }//Ctrl+H隐藏窗口
if (e.KeyData == (Keys.C | Keys.Control)) { this.Close(); }//Ctrl+C 关闭窗口
if (e.KeyData == (Keys.A | Keys.Control | Keys.Alt)) { this.Text = "你发现了什么?"; }//Ctrl+Alt+A
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
kh.UnHook();
}
}
代码添加完毕后,运行调试。当按下Ctrl+H是窗口隐藏,当按下Ctrl+S窗口显示,当按下Ctrl+C时窗口关闭,开着QQ按下Ctrl+Alt+A时...(会出现什么呢?这个要你自己去发现哦)。
- C# 构子的实现
- C#中MDI子窗体的Singleton模式实现
- C#子窗口调用父窗口控件的委托实现
- C#用panel实现子窗体的切换
- C#子窗口调用父窗口控件的委托实现
- C#子窗口调用父窗口控件的委托实现
- c# 子菜单前边的对勾实现方法
- C# 实现子窗体控制父窗体的方法
- C# 实现求一个字符串的子串问题
- C#利用子窗体中的构造函数 (实现了父窗体给子窗体的传值,但是子窗体的值回传暂未实现)
- 用C#简单实现主表与子表的联动关系
- C#实现修改目录文件下所有子文件的名称---按规律重命名
- C# 实现MDI子窗体只打开一个(打开新的窗口,关闭其他窗口)
- C#用委托的方法实现点击子窗体控件来刷新父窗体
- 有关求最大不含重复字符子字符串算法的C#实现
- C# 在主窗口中打开一个带有计算器功能的子窗口,有三种实现方法
- 【C#】C#实现嵌入式窗体(弹出的子窗体在父窗体内)
- Sift描述子的实现
- VB操作字符串总结
- C语言中字符串处理函数拾锦
- 关于死刑,何谓善?有感于电影《凝望深渊》
- 面试高频题
- Ubuntu下codeblocks的气泡球程序(四)
- C# 构子的实现
- HDU5007 Post Robot
- HDU5007 Post Robot
- 2015百度校园招聘机器学习/数据挖掘工程师笔试题(笔试时间:2014-9-14,哈尔滨站)
- ubuntu10.04的学习小结
- 异常处理
- Q&A about the _method_ meaning?
- 面向对象程序设计上机练习七(类和对象)
- 电面小记