using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Reflection; namespace 梦琪动漫屋
{
/// <summary>
/// 键盘钩子/// </summary>
class KeyboardHook
{
public event KeyEventHandler KeyDownEvent;
public event KeyPressEventHandler KeyPressEvent;
public event KeyEventHandler KeyUpEvent; public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
static int hKeyboardHook = ; //声明键盘钩子处理的初始值
//值在Microsoft SDK的Winuser.h里查询
// http://www.bianceng.cn/Programming/csharp/201410/45484.htm
public const int WH_KEYBOARD_LL = ; //线程键盘钩子监听鼠标消息设为2,全局键盘监听鼠标消息设为13
HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型
//键盘结构
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode; //定一个虚拟键码。该代码必须有一个价值的范围1至254
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, Int32 wParam, IntPtr lParam); // 取得当前线程编号(线程钩子需要用到)
[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId(); //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name); public void Start()
{
// 安装键盘钩子
if (hKeyboardHook == )
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), );
//hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
//************************************
//键盘线程钩子
//SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),
//键盘全局钩子,需要引用空间(using System.Reflection;)
//SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
//
//关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:
//idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13,
//线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的
//线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何
//消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子
//程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符
//如果为0,钩子子程与所有的线程关联,即为全局钩子
//************************************
//如果SetWindowsHookEx失败
if (hKeyboardHook == )
{
Stop();
throw new Exception("安装键盘钩子失败");
}
}
}
public void Stop()
{
bool retKeyboard = true; if (hKeyboardHook != )
{
retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = ;
} if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
}
//ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符
[DllImport("user32")]
public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。
int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压)
byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。
int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. //获取按键的状态
[DllImport("user32")]
public static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern short GetKeyState(int vKey); private const int WM_KEYDOWN = 0x100;//KEYDOWN
private const int WM_KEYUP = 0x101;//KEYUP
private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
private const int WM_SYSKEYUP = 0x105;//SYSKEYUP private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
// 侦听键盘事件
if ((nCode >= ) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
{
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
// raise KeyDown
if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDownEvent(this, e);
} //键盘按下
if (KeyPressEvent != null && wParam == WM_KEYDOWN)
{
byte[] keyState = new byte[];
GetKeyboardState(keyState); byte[] inBuffer = new byte[];
if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == )
{
KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[]);
KeyPressEvent(this, e);
}
} // 键盘抬起
if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUpEvent(this, e);
} }
//如果返回1,则结束消息,这个消息到此为止,不再传递。
//如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
~KeyboardHook()
{
Stop();
}
}
}

如何使用上面的工具类?

//0.准备工作 
//把上面的工具类添加到项目中

//1.首先导入需要的命名空间 
using System.Runtime.InteropServices; //调用WINDOWS API函数时要用到 
using Microsoft.Win32; //写入注册表时要用到

//2.安装Hook,在程序入口中写上下面的代码(本例中用了WinForm,在Form的构造方法中安装Hook即可) 
//安装键盘钩子 
k_hook = new KeyboardHook(); 
k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);//钩住键按下 
k_hook.Start();//安装键盘钩子

//3.判断输入键值(实现KeyDown事件) 
private void hook_KeyDown(object sender, KeyEventArgs e) 

//判断按下的键(Alt + A) 
if (e.KeyValue == (int)Keys.A && (int)Control.ModifierKeys == (int)Keys.Alt) 

System.Windows.Forms.MessageBox.Show(“按下了指定快捷键组合”); 


//注意几种不同的键值判断: 
//1>.单普通键(例如A) 
//2>.单控制键+单普通键(例如Ctrl+A) 
//3>.多控制键+单普通键(例如Ctrl+Alt+A) 
//上面的代码中演示了2,其它情况以此类推,无非就是添几个条件再&&起来就好

原文地址:http://blog.csdn.net/u014434080/article/details/51513197

【转】【C#】全局键盘监听的更多相关文章

  1. C#全局键盘监听(Hook)

    一.为什么需要全局键盘监听? 在某些情况下应用程序需要实现快捷键执行特定功能,例如大家熟知的QQ截图功能Ctrl+Alt+A快捷键,只要QQ程序在运行(无论是拥有焦点还是处于后台运行状态),都可以按下 ...

  2. js 获取当前焦点所在的元素、给元素和input控件添加键盘监听事件、添加页面级的键盘监听事件

    页面级的键盘监听事件 document.onkeydown = function (event) { var e = event || window.event || arguments.callee ...

  3. 使用HTML+CSS,jQuery编写的简易计算器后续(添加了键盘监听)

    之前发布了一款简易的计算器,今天做了一下修改,添加了键盘监听事件,不用再用鼠标点点点啦 JS代码: var yunSuan = 0;// 运算符号,0-无运算;1-加法;2-减法;3-乘法;4-除法 ...

  4. [置顶] java Gui 键盘监听事件

    简单写一个java Gui键盘监听事件,实现的效果就是按下键盘控制台输出你按下的键.比如:按下A控制台就输出A 效果如图: 以下把实现的效果分为几个步骤: 1.新建一个窗体类继承窗体: 2.给这个窗体 ...

  5. java swing button和键盘监听冲突问题

    原因: 点击button会让jframe失去焦点,然后键盘监听不起作用 解决: 让jframe重新获取焦点就行了 jf.setFocusable(true); // JFrame jf = new J ...

  6. ios --键盘监听JYKeyBoardListener

    没有前言,就是一个简单的键盘监听,自动调整输入框的位置不被键盘遮挡 .h // // JYKeyBoardListener.h // // Created by JianF.Sun on 17/9/2 ...

  7. JPanel添加键盘监听事件

    因为在自己的游戏需求中谢了要用键盘控制飞机的移动,所以用到键盘监听事件,但是使用了JPanel之后添加了键盘监听事件,按相应的方向键飞机并没有反应.但是如果是为JFrame的内容面板加则会有反应. 为 ...

  8. Android之键盘监听的执行机理【看清键盘监听的本质】【入门版】

    以EditText为例: 1.Activity本身也有按键监听 editText按键监听与Activity按键监听关系: Activity本身也有按键监听 并且分按下和松开两个事件监听 editTex ...

  9. 第35天学习打卡(输入框 TextField监听 简易计算器,组合+内部类回顾复习 画笔 鼠标监听 窗口监听 键盘监听)

    1.输入框 TextField监听  package com.kuang.lesson02; ​ import java.awt.*; import java.awt.event.ActionEven ...

随机推荐

  1. Linux中断 - GIC代码分析

    一.前言 GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器,其architecture specification目前有四个版本,V1-V4(V ...

  2. telnet远程登录协议

    什么是Telnet? 对于Telnet的认识,不同的人持有不同的观点,可以把Telnet当成一种通信协议,但是对于入侵者而言,Telnet只是一种远程登录的工具.一旦入侵者与远程主机建立了Telnet ...

  3. Eclipse使用git最基本流程(提交远程仓库的方法)

    注册一个github账号 注册完成之后,点击右上角的settings(就是那个齿轮,设置的图标) Step6 Egit的使用 首先,登入你的github账号,点击加号,选择New repositror ...

  4. [QT] 小知识集锦

    qt 中关于 QWidget 的背景颜色和背景图片的设置 首先设置autoFillBackground 属性为真 然后定义一个QPalette 对象 设置QPalette 对象的背景属性(颜色或图片) ...

  5. [学习笔记]Spring依赖注入

    依赖: 典型的企业应用程序不可能由单个对象(在spring中,也可称之bean)组成,再简单的应用也是由几个对象相互配合工作的,这一章主要介绍bean的定义以及bean之间的相互协作. 依赖注入: s ...

  6. PHP5.5四种序列化性能对照

    json_encode,serialize,igbinary,msgpack四种序列化方式,在之前已经有过相关的測试,PHP5.5这方面的測试临时没有,这次測试基于PHP5.5,而且測试用例,http ...

  7. QT中布局器的addStretch函数使用效果

    QBoxLayout中addStretch 函数说明: void QBoxLayout::addStretch(int stretch = 0) Adds a stretchable space (a ...

  8. 一文读懂什么是Java中的自动拆装箱

    基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型.它们是我们编程中使用最频繁的类型. Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为 ...

  9. MySQL - 1093异常 - You can't specify target table 't' for update in FROM clause

    有一个表示地区的表,表结构与数据大概如下表. ID NAME PARENT_ID 1 中国 2 广东省 1 3 广州市 2 4 荔湾区 3 5 越秀区 3 6 番禺区 3 7 小谷围街道 6 现为了查 ...

  10. windows 7/mac编译cocos2d-x-3.2*的android工程报错

    开始学习cocos2d-x-3.* 凭着对2.*的各个版本的认识和升级的经验,本以为直接用最新的3.2rc0版本练手应该没有问题,结果一上来就是一个大坑.你妹! Android NDK: Invali ...