关于全局键盘钩子问题

aroppo 2010-04-29 02:49:26

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace HookTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
static int hHook = 0;
public const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
public class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

//设置钩子
[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, IntPtr wParam, IntPtr lParam);
//取得模块句柄
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
//寻找目标进程窗口
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//设置进程窗口到最前
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
//模拟键盘事件
[DllImport("User32.dll")]
public static extern void keybd_event(Byte bVk, Byte bScan, Int32 dwFlags, Int32 dwExtraInfo);
//释放按键的常量
const int KEYEVENTF_KEYUP = 2;

public static int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{ //监控用户键盘输入
KeyBoardHookStruct input = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
if (input.vkCode == (int)Keys.Q)
{
byte VK_Q = (byte)Keys.NumPad7;
keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0); //松开小键盘7
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
public void Hook_Start()
{
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
}

}

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("开启");
Hook_Start();


}

private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("关闭");
UnhookWindowsHookEx(hHook);
}
}
}

我想模拟键盘输入。当按下Q时,相当于按下小键盘7
但是为什么运行后点击Q键会出现三个字符 7q7 ?
...全文
459 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
aroppo 2010-04-29
  • 打赏
  • 举报
回复

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace HookTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
static int hHook = 0;
public const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
public class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}

//设置钩子
[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, IntPtr wParam, IntPtr lParam);
//取得模块句柄
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
//寻找目标进程窗口
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//设置进程窗口到最前
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
//模拟键盘事件
[DllImport("User32.dll")]
public static extern void keybd_event(Byte bVk, Byte bScan, Int32 dwFlags, Int32 dwExtraInfo);
//释放按键的常量
const int KEYEVENTF_KEYUP = 2;
const int WM_KEYDOWN = 0x0100;

public static int KeyBoardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{

//监控用户键盘输入
KeyBoardHookStruct input = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
byte VK_Q = (byte)Keys.NumPad7;
if (wParam == (IntPtr)WM_KEYDOWN && input.vkCode == (int)Keys.Q)
{
keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0); //松开小键盘7
return 1;
}
if (input.vkCode == (int)Keys.Home)
{
IntPtr wcHandle = FindWindow(null, "Warcraft III");
if (wcHandle != IntPtr.Zero)
{
SetForegroundWindow(wcHandle);
byte VK_NUM1 = 219;
keybd_event(VK_NUM1, 0, 0, 0);
byte VK_NUM2 = 221;
keybd_event(VK_NUM2, 0, 0, 0);
}
}
// if (input.vkCode == (int)Keys.End)
// new Form1().Hook_Clear();
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
public void Hook_Clear()
{
bool retKeyboard = true;
if (hHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hHook);
hHook = 0;
}
//如果去掉钩子失败.
if (!retKeyboard) throw new Exception("UnhookWindowsHookEx failed.");
}



public void Hook_Start()
{
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
}

}

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("开启");
Hook_Start();


}

private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("关闭");
UnhookWindowsHookEx(hHook);
}
}
}


这样也可以解决。
aroppo 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 mngzilin 的回复:]
if(input.flags==0)//如果按下Q
{
keybd_event(VK_Q, 0, 0, 0);
}
else//如果释放Q
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0);
[/Quote]
谢谢。问题已经解决了。但这个方法更好用。能不能告诉我,input.flags == 0;这句是什么意思。flags这个参数是用来做什么的?

xingyuebuyu 2010-04-29
  • 打赏
  • 举报
回复
mngzilin 2010-04-29
  • 打赏
  • 举报
回复
if(input.flags==0)//如果按下Q
{
keybd_event(VK_Q, 0, 0, 0);
}
else//如果释放Q
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0);
aroppo 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 deknight 的回复:]
mark
[/Quote]
这是什么意思?
我只是想知道怎么样区别开KEY_UP和KEY_DOWN事件。通过lParam这个参数可以么?如果可以怎么做?
deknight 2010-04-29
  • 打赏
  • 举报
回复
mark
aroppo 2010-04-29
  • 打赏
  • 举报
回复

if (input.vkCode == (int)Keys.Q)
{
byte VK_Q = (byte)Keys.NumPad7;
keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0); //松开小键盘7
return 1;
}

按下和弹起调用两次,所以出现两个77.如何保留一个?
aroppo 2010-04-29
  • 打赏
  • 举报
回复
我找了下,发现键盘按下和弹起时产生的两个事件都要调用Hook函数,怎么样才可以保留一个呢?
testtestett 2010-04-29
  • 打赏
  • 举报
回复
我觉得你还是先了解消息机制
cyhf00808 2010-04-29
  • 打赏
  • 举报
回复
学 习
testtestett 2010-04-29
  • 打赏
  • 举报
回复
c#能改键?
aroppo 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 gws044010607 的回复:]
你把这句话 return CallNextHookEx(hHook, nCode, wParam, lParam);
改为 rerurn 1;
就知道为什么了
[/Quote]
我改了仍然不知道问题所在。希望你可以直接说下。
我是参照下面这篇文章写的。
http://developer.51cto.com/art/200909/148729.htm
aroppo 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 mngzilin 的回复:]
既然要将Q替换为7,就因该不让键盘消息Q继续传导下一个hook链。
================

if (input.vkCode == (int)Keys.Q)
{
byte VK_Q = (byte)Keys.NumPad7;
keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
keybd_event(VK_Q, 0, KEYEVEN……
[/Quote]
我试了,效果是一样的。仍然出现 7q7 只要这里的return 值为0就会这样,不为0键盘就无法输入。实在不明白为什么?我是参照http://developer.51cto.com/art/200909/148729.htm这里写的。
mngzilin 2010-04-29
  • 打赏
  • 举报
回复
return 0;
============》》》
return 1;
mngzilin 2010-04-29
  • 打赏
  • 举报
回复
既然要将Q替换为7,就因该不让键盘消息Q继续传导下一个hook链。
================

if (input.vkCode == (int)Keys.Q)
{
byte VK_Q = (byte)Keys.NumPad7;
keybd_event(VK_Q, 0, 0, 0);//按下小键盘7
keybd_event(VK_Q, 0, KEYEVENTF_KEYUP, 0); //松开小键盘7
return 0;
}
else return CallNextHookEx(hHook, nCode, wParam, lParam);
CosmoKey 2010-04-29
  • 打赏
  • 举报
回复
你是不是一直按住的??
如果是应该狂弹出吧...

因为每次结束调用下一个钩子,所以,当你还在按住Q时.还会继续调用方法的
testtestett 2010-04-29
  • 打赏
  • 举报
回复
你把这句话 return CallNextHookEx(hHook, nCode, wParam, lParam);
改为 rerurn 1;
就知道为什么了
aroppo 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 gws044010607 的回复:]
可能是模拟键盘产生了一个KEYDOWN 和一个KEYCHAR,至于那个q是肯定会出现的。
[/Quote]
我想的是Num7代替了q啊。怎么一定会出现一个q?实在不解。能详细解释下吗?谢谢了。
testtestett 2010-04-29
  • 打赏
  • 举报
回复
可能是模拟键盘产生了一个KEYDOWN 和一个KEYCHAR,至于那个q是肯定会出现的。
加载更多回复(2)

110,586

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧