"拍牌神器"是怎样炼成的(三)---注册全局热键

要想在上海拍牌的超低中标率中把握机会、占得先机,您不仅需要事先准备好最优的竞拍策略,还要制定若干套应急预案,应对不时之需。既定策略交给计算机自动执行,没有问题。可是谁来召唤应急预案呢?使用全局热键应该是个不错的选择。

正确使用全局热键,您得按下面的步骤来:

  1. 向系统注册HotKey(可以是一个键,也可以是组合键)。
  2. 接收系统WM_HOTKEY消息,触发你的HOTKEY事件。
  3. 完成你的事件处理程序。
  4. 程序结束时,记得注销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的例子中已经包含,可在这里下载

posted @ 2016-04-21 11:10  鼻涕鱼  阅读(1226)  评论(0)    收藏  举报