要想在上海拍牌的超低中标率中把握机会、占得先机,您不仅需要事先准备好最优的竞拍策略,还要制定若干套应急预案,应对不时之需。既定策略交给计算机自动执行,没有问题。可是谁来召唤应急预案呢?使用全局热键应该是个不错的选择。
正确使用全局热键,您得按下面的步骤来:
- 向系统注册HotKey(可以是一个键,也可以是组合键)。
- 接收系统WM_HOTKEY消息,触发你的HOTKEY事件。
- 完成你的事件处理程序。
- 程序结束时,记得注销HotKey。
注册HotKey
先来看看,我们需要用到哪些WinAPI函数:
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern ushort GlobalAddAtom(string lpString);
GlobalAddAtom函数的功能是向系统全局原子表添加原子,全局原子表是系统用来共享信息的,我们在这里用它产生一个唯一标识号,供RegisterHotKey函数使用,避免注册的热键与其他程序的热键冲突。
RegisterHotKey注册热键函数的3个传入参数含义分别如下
- hWnd 响应热键事件的窗口句柄。
- id 一个唯一标识号,通过GlobalAddAtom函数获得
- fsModifiers 组合键CTRL、ALT、SHIFT等键(我一般不用,加个组合键影响操作速度)。
- vk 热键键值
注销HotKey
注册的逆向操作而已,仅给出WinAPI函数声明吧。
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
static extern ushort GlobalDeleteAtom(ushort nAtom);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);
接收HotKey消息
我们需要写一个实现IMessageFilter接口的类,并把这个类实例通过System.Windows.Forms.Application.AddMessageFilter(IMessageFilter)方法添加到消息筛选器中去,当消息产生时会调用IMessageFilter接口的PreFilterMessage方法,通过PreFilterMessage方法可以触发我们自己的消息处理函数。
下面的代码,定义了一个简单的筛选器类:
public delegate void HotkeyEventHandler(int HotKeyID);
public class HotKey : System.Windows.Forms.IMessageFilter
{
IntPtr hWnd;
readonly int WM_HOTKEY = 0x312;
public enum KeyFlags { MOD_ALT = 0x1, MOD_CONTROL = 0x2, MOD_SHIFT = 0x4, MOD_WIN = 0x8 }
System.Collections.Hashtable keyIDs = new System.Collections.Hashtable();
public event HotkeyEventHandler OnHotkey;
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern ushort GlobalAddAtom(string lpString);
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
static extern ushort GlobalDeleteAtom(ushort nAtom);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public HotKey(IntPtr hWnd)
{
this.hWnd = hWnd;
System.Windows.Forms.Application.AddMessageFilter(this); //添加到消息筛选器
}
public int RegisterHotkey(System.Windows.Forms.Keys Key, KeyFlags keyflags)
{
String keyname = System.Guid.NewGuid().ToString();
int hotkeyid = GlobalAddAtom(keyname); //添加全局原子表
RegisterHotKey((IntPtr)hWnd, hotkeyid, (UInt32)keyflags, (UInt32)Key); //注册热键
keyIDs.Add(keyname,hotkeyid);
return hotkeyid;
}
public void UnregisterHotkeys() //注销HotKeys
{
System.Windows.Forms.Application.RemoveMessageFilter(this);
foreach (int key in keyIDs.Values)
{
UnregisterHotKey(hWnd, key);
GlobalDeleteAtom((ushort)key);
}
}
public bool PreFilterMessage(ref System.Windows.Forms.Message m) //IMessageFilter接口实现
{
if (m.Msg == WM_HOTKEY)
{
if (OnHotkey != null)
{
foreach (int key in keyIDs.Values)
{
if ((int)m.WParam == key)
{
OnHotkey((int)m.WParam);
return true;
}
}
}
}
return false;
}
}
代码中如何使用
在WinForm程序中,调用方法如下:
HotKey hotKey;
private void Form1_Load(object sender, EventArgs e)
{
...
hotKey = new HotKey(this.Handle);
hotKey.RegisterHotkey(Keys.F2, 0);
hotKey.OnHotkey += hotkey_OnHotkey;
}
void hotkey_OnHotkey(int HotKeyID)
{
...
MessageBox.Show("OnHotkey" + HotKeyID);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (hotKey != null)
hotKey.UnregisterHotkeys();
}
结束语
本讲结束了,如何使用计算机替代手
的工作进行拍牌也讲完了,接下来,我们要开始介绍如何用计算机替代眼
的工作(验证码识别)。
本次的例子,在键鼠模拟之WinAPI的例子中已经包含,可在这里下载。