清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

原创 C#利用钩子控制鼠标【月儿原创】 收藏

C#利用钩子控制鼠标

作者:清清月儿

主页:http://blog.csdn.net/21aspnet/           时间:2007.5.11

工作中有这样的需求,某个控件panel的子控件textbox要实现只留鼠标右键copy,注意同时还不能影响其它panel的子控件textbox,怎么办?
答案是只有用钩子,在codeporject上找到这么一个钩子。

如图所示,第一个文本框只有copy功能。


UserActivityHook.cs


using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;

namespace gma.System.Windows
{
 
/// <summary>
 
/// This class allows you to tap keyboard and mouse and / or to detect their activity even when an 
 
/// application runes in background or does not have any user interface at all. This class raises 
 
/// common .NET events with KeyEventArgs and MouseEventArgs so you can easily retrieve any information you need.
 
/// </summary>

 public class UserActivityHook
 
{
  
Windows structure definitions

  
Windows function imports

  
Windows constants

  
/// <summary>
  
/// Creates an instance of UserActivityHook object and sets mouse and keyboard hooks.
  
/// </summary>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>

  public UserActivityHook()
  
{
   Start();
  }


  
/// <summary>
  
/// Creates an instance of UserActivityHook object and installs both or one of mouse and/or keyboard hooks and starts rasing events
  
/// </summary>
  
/// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>
  
/// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>
  
/// <remarks>
  
/// To create an instance without installing hooks call new UserActivityHook(false, false)
  
/// </remarks>

  public UserActivityHook(bool InstallMouseHook, bool InstallKeyboardHook)
  
{
   Start(InstallMouseHook, InstallKeyboardHook);
  }


  
/// <summary>
  
/// Destruction.
  
/// </summary>

  ~UserActivityHook()
  
{
   
//uninstall hooks and do not throw exceptions
   Stop(truetruefalse);
  }


  
/// <summary>
  
/// Occurs when the user moves the mouse, presses any mouse button or scrolls the wheel
  
/// </summary>

  public event MouseEventHandler OnMouseActivity;
  
/// <summary>
  
/// Occurs when the user presses a key
  
/// </summary>

  public event KeyEventHandler KeyDown;
  
/// <summary>
  
/// Occurs when the user presses and releases 
  
/// </summary>

  public event KeyPressEventHandler KeyPress;
  
/// <summary>
  
/// Occurs when the user releases a key
  
/// </summary>

  public event KeyEventHandler KeyUp;


  
/// <summary>
  
/// Stores the handle to the mouse hook procedure.
  
/// </summary>

  private int hMouseHook = 0;
  
/// <summary>
  
/// Stores the handle to the keyboard hook procedure.
  
/// </summary>

  private int hKeyboardHook = 0;


  
/// <summary>
  
/// Declare MouseHookProcedure as HookProc type.
  
/// </summary>

  private static HookProc MouseHookProcedure;
  
/// <summary>
  
/// Declare KeyboardHookProcedure as HookProc type.
  
/// </summary>

  private static HookProc KeyboardHookProcedure;


  
/// <summary>
  
/// Installs both mouse and keyboard hooks and starts raising events
  
/// </summary>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>

  public void Start()
  
{
   
this.Start(truetrue);
  }


  
/// <summary>
  
/// Installs both or one of mouse and/or keyboard hooks and starts raising events
  
/// </summary>
  
/// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>
  
/// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>

  public void Start(bool InstallMouseHook, bool InstallKeyboardHook)
  
{
   
// install Mouse hook only if it is not installed and must be installed
   if (hMouseHook == 0 && InstallMouseHook)
   
{
    
// Create an instance of HookProc.
    MouseHookProcedure = new HookProc(MouseHookProc);
    
//install hook
    hMouseHook = SetWindowsHookEx(
     WH_MOUSE_LL,
     MouseHookProcedure,
     Marshal.GetHINSTANCE(
     Assembly.GetExecutingAssembly().GetModules()[
0]),
     
0);
    
//If SetWindowsHookEx fails.
    if (hMouseHook == 0)
    
{
     
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
     int errorCode = Marshal.GetLastWin32Error();
     
//do cleanup
     Stop(truefalsefalse);
     
//Initializes and throws a new instance of the Win32Exception class with the specified error. 
     throw new Win32Exception(errorCode);
    }

   }


   
// install Keyboard hook only if it is not installed and must be installed
   if (hKeyboardHook == 0 && InstallKeyboardHook)
   
{
    
// Create an instance of HookProc.
    KeyboardHookProcedure = new HookProc(KeyboardHookProc);
    
//install hook
    hKeyboardHook = SetWindowsHookEx(
     WH_KEYBOARD_LL,
     KeyboardHookProcedure,
     Marshal.GetHINSTANCE(
     Assembly.GetExecutingAssembly().GetModules()[
0]),
     
0);
    
//If SetWindowsHookEx fails.
    if (hKeyboardHook == 0)
    
{
     
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
     int errorCode = Marshal.GetLastWin32Error();
     
//do cleanup
     Stop(falsetruefalse);
     
//Initializes and throws a new instance of the Win32Exception class with the specified error. 
     throw new Win32Exception(errorCode);
    }

   }

  }


  
/// <summary>
  
/// Stops monitoring both mouse and keyboard events and rasing events.
  
/// </summary>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>

  public void Stop()
  
{
   
this.Stop(truetruetrue);
  }


  
/// <summary>
  
/// Stops monitoring both or one of mouse and/or keyboard events and rasing events.
  
/// </summary>
  
/// <param name="UninstallMouseHook"><b>true</b> if mouse hook must be uninstalled</param>
  
/// <param name="UninstallKeyboardHook"><b>true</b> if keyboard hook must be uninstalled</param>
  
/// <param name="ThrowExceptions"><b>true</b> if exceptions which occured during uninstalling must be thrown</param>
  
/// <exception cref="Win32Exception">Any windows problem.</exception>

  public void Stop(bool UninstallMouseHook, bool UninstallKeyboardHook, bool ThrowExceptions)
  
{
   
//if mouse hook set and must be uninstalled
   if (hMouseHook != 0 && UninstallMouseHook)
   
{
    
//uninstall hook
    int retMouse = UnhookWindowsHookEx(hMouseHook);
    
//reset invalid handle
    hMouseHook = 0;
    
//if failed and exception must be thrown
    if (retMouse == 0 && ThrowExceptions)
    
{
     
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
     int errorCode = Marshal.GetLastWin32Error();
     
//Initializes and throws a new instance of the Win32Exception class with the specified error. 
     throw new Win32Exception(errorCode);
    }

   }


   
//if keyboard hook set and must be uninstalled
   if (hKeyboardHook != 0 && UninstallKeyboardHook)
   
{
    
//uninstall hook
    int retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
    
//reset invalid handle
    hKeyboardHook = 0;
    
//if failed and exception must be thrown
    if (retKeyboard == 0 && ThrowExceptions)
    
{
     
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
     int errorCode = Marshal.GetLastWin32Error();
     
//Initializes and throws a new instance of the Win32Exception class with the specified error. 
     throw new Win32Exception(errorCode);
    }

   }

  }



  
/// <summary>
  
/// A callback function which will be called every time a mouse activity detected.
  
/// </summary>
  
/// <param name="nCode">
  
/// [in] Specifies whether the hook procedure must process the message. 
  
/// If nCode is HC_ACTION, the hook procedure must process the message. 
  
/// If nCode is less than zero, the hook procedure must pass the message to the 
  
/// CallNextHookEx function without further processing and must return the 
  
/// value returned by CallNextHookEx.
  
/// </param>
  
/// <param name="wParam">
  
/// [in] Specifies whether the message was sent by the current thread. 
  
/// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
  
/// </param>
  
/// <param name="lParam">
  
/// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
  
/// </param>
  
/// <returns>
  
/// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
  
/// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
  
/// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
  
/// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
  
/// procedure does not call CallNextHookEx, the return value should be zero. 
  
/// </returns>

  private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
  
{
   
// if ok and someone listens to our events
   if ((nCode >= 0&& (OnMouseActivity != null))
   
{
    
//Marshall the data from callback.
    MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

    
//detect button clicked
    MouseButtons button = MouseButtons.None;
    
short mouseDelta = 0;
    
switch (wParam)
    
{
     
case WM_LBUTTONDOWN:
      
//case WM_LBUTTONUP: 
      
//case WM_LBUTTONDBLCLK: 
      button = MouseButtons.Left;
      
break;
     
case WM_RBUTTONDOWN:
      
//case WM_RBUTTONUP: 
      
//case WM_RBUTTONDBLCLK: 
      button = MouseButtons.Right;
      
break;
     
case WM_MOUSEWHEEL:
      
//If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 
      
//One wheel click is defined as WHEEL_DELTA, which is 120. 
      
//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
      mouseDelta = (short)((mouseHookStruct.mouseData >> 16& 0xffff);
      
//TODO: X BUTTONS (I havent them so was unable to test)
      
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 
      
//or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
      
//and the low-order word is reserved. This value can be one or more of the following values. 
      
//Otherwise, mouseData is not used. 
      break;
    }


    
//double clicks
    int clickCount = 0;
    
if (button != MouseButtons.None)
     
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
     
else clickCount = 1;

    
//generate event 
    MouseEventArgs e = new MouseEventArgs(
     button,
     clickCount,
     mouseHookStruct.pt.x,
     mouseHookStruct.pt.y,
     mouseDelta);
    
//raise it
    OnMouseActivity(this, e);
   }

   
//call next hook
   return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
  }


  
/// <summary>
  
/// A callback function which will be called every time a keyboard activity detected.
  
/// </summary>
  
/// <param name="nCode">
  
/// [in] Specifies whether the hook procedure must process the message. 
  
/// If nCode is HC_ACTION, the hook procedure must process the message. 
  
/// If nCode is less than zero, the hook procedure must pass the message to the 
  
/// CallNextHookEx function without further processing and must return the 
  
/// value returned by CallNextHookEx.
  
/// </param>
  
/// <param name="wParam">
  
/// [in] Specifies whether the message was sent by the current thread. 
  
/// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
  
/// </param>
  
/// <param name="lParam">
  
/// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
  
/// </param>
  
/// <returns>
  
/// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
  
/// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
  
/// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
  
/// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
  
/// procedure does not call CallNextHookEx, the return value should be zero. 
  
/// </returns>

  private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
  
{
   
//indicates if any of underlaing events set e.Handled flag
   bool handled = false;
   
//it was ok and someone listens to events
   if ((nCode >= 0&& (KeyDown != null || KeyUp != null || KeyPress != null))
   
{
    
//read structure KeyboardHookStruct at lParam
    KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
    
//raise KeyDown
    if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
    
{
     Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
     KeyEventArgs e 
= new KeyEventArgs(keyData);
     KeyDown(
this, e);
     handled 
= handled || e.Handled;
    }


    
// raise KeyPress
    if (KeyPress != null && wParam == WM_KEYDOWN)
    
{
     
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80== 0x80 ? true : false);
     
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

     
byte[] keyState = new byte[256];
     GetKeyboardState(keyState);
     
byte[] inBuffer = new byte[2];
     
if (ToAscii(MyKeyboardHookStruct.vkCode,
      MyKeyboardHookStruct.scanCode,
      keyState,
      inBuffer,
      MyKeyboardHookStruct.flags) 
== 1)
     
{
      
char key = (char)inBuffer[0];
      
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
      KeyPressEventArgs e 
= new KeyPressEventArgs(key);
      KeyPress(
this, e);
      handled 
= handled || e.Handled;
     }

    }


    
// raise KeyUp
    if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
    
{
     Keys keyData 
= (Keys)MyKeyboardHookStruct.vkCode;
     KeyEventArgs e 
= new KeyEventArgs(keyData);
     KeyUp(
this, e);
     handled 
= handled || e.Handled;
    }


   }


   
//if event handled in application do not handoff to other listeners
   if (handled)
    
return 1;
   
else
    
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
  }

 }

}


Form1.cs

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication2
{
 
/// <summary>
 
/// Form1 的摘要说明。清清月儿主页:http://blog.csdn.net/21aspnet/   
/// </summary>

 public class Form1 : System.Windows.Forms.Form
 
{
  
private System.Windows.Forms.TextBox textBox1;
  
private System.Windows.Forms.TextBox textBox2;
  
private System.Windows.Forms.Panel panel1;
  
/// <summary>
  
/// 必需的设计器变量。
  
/// </summary>

  private System.ComponentModel.Container components = null;

  
public Form1()
  
{
   
//
   
// Windows 窗体设计器支持所必需的
   
//
   InitializeComponent();

   
//
   
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   
//
  }


  
/// <summary>
  
/// 清理所有正在使用的资源。
  
/// </summary>

  protected override void Dispose( bool disposing )
  
{
   
if( disposing )
   
{
    
if (components != null
    
{
     components.Dispose();
    }

   }

   
base.Dispose( disposing );
  }


  
Windows 窗体设计器生成的代码

  
/// <summary>
  
/// 应用程序的主入口点。
  
/// </summary>

  [STAThread]
  
static void Main() 
  
{
   Application.Run(
new Form1());

  }


  
  
public void MyKeyDown(object sender, KeyEventArgs e)
  
{
  }


  
public void MyKeyPress(object sender, KeyPressEventArgs e)
  
{
  }


  
public void MyKeyUp(object sender, KeyEventArgs e)
  
{
  }

  

  
void choose_OnMouseActivity(object sender, MouseEventArgs e)
  
{
                                          
//自定义右键
   
//if (ActiveControl.Parent == panel1) 备用
   
//if (ActiveControl.Parent is System.Windows.Forms.Panel) 备用
   if (ActiveControl == textBox1)
   
{
    MenuItem copy 
= new MenuItem("copy");
    copy.Click 
+= new EventHandler(copy_Click);            
    MenuItem[] menuItems 
= new MenuItem[] { copy };

    ContextMenu buttonMenu 
= new ContextMenu(menuItems);           
    textBox1.ContextMenu 
= buttonMenu;
    
//this.ActiveControl.ContextMenu = buttonMenu; 备用
   }

  }


  
private void copy_Click(object sender, EventArgs e)
  
{
   
    Clipboard.SetDataObject(textBox1.SelectedText) ; 
//复制到剪切板
   
  }


  
private void Form1_Load(object sender, System.EventArgs e)
  
{
                                          
//初始化
   gma.System.Windows.UserActivityHook  choosesc=new gma.System.Windows.UserActivityHook();
   choosesc.OnMouseActivity 
+= new MouseEventHandler(choose_OnMouseActivity);
//   choosesc.KeyDown += new KeyEventHandler(MyKeyDown);
//   choosesc.KeyPress += new KeyPressEventHandler(MyKeyPress);
//   choosesc.KeyUp += new KeyEventHandler(MyKeyUp);

  }


 }

}


说明:这个钩子有点问题,就是一次只能打开一个窗口(如果该窗口使用钩子),打开后一定要关闭否则出问题,后果很严重!!! 

经典钩子:

之一:http://www.codeproject.com/csharp/globalhook.asp

之二:http://www.codeproject.com/csharp/GlobalSystemHook.asp

发表于 @ 2007年05月11日 09:29:00|评论(loading...)

新一篇: asp.net千奇百怪的日历【月儿原创】  | 旧一篇: C#中判断空字符串的3种方法性能分析【月儿原创】

用户操作
[即时聊天] [发私信] [加为好友]
清清月儿
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
清清月儿的公告
文章分类
收藏
    .NET 工具
    C# to VB.NET Translator
    Fiddler
    FxCop代码标准检测工具
    httpwatch
    ieinspector
    IETester
    Memcached
    Multiple IE
    Nbear
    Nunit单元测试
    pushlets
    Tab集合
    VB.NET and C# Comparison
    VB.NET 代码转为C#
    网站国际排名查询工具
    .NET 下载/讲座视频
    chinaitlab
    enfull
    Visual Studio 2005 的工具
    wrox出版社书刊代码下载
    中国台湾微软MSDN
    中文MSDN WebCast网络广播全部下载列表
    源码之家
    .NET 优秀Blog
    cathsfz
    cnkiminzhuhu
    cuike519的专栏
    dahuzizyd的专栏
    DotNet技术交流乐园
    DotNet男孩社区
    dudu
    gztoby
    IT Crazy
    Kemin's booootLog
    kimyoo(RSS)
    Leoo2sk
    LoveCherry
    MSDN每日追踪
    Nios.Org
    phphot
    Teddy's Knowledge Base
    Think Different and Think More
    Visual Studio.net专栏
    WCF Tools 中国研发团队的专栏
    体验ASP.NET 2.0新特性
    刘洪峰
    天轰穿
    孟宪会
    宝玉
    开心就好【博客堂】
    张子阳
    彭斌
    思归呓语
    木子 [I am praying]
    李会军
    李洪根【VB】
    永春阁
    汉飞扬【Vista】
    涂曙光【SharePoint】
    理想&美人(RSS)
    维生素C.net
    网际浪子
    葛涵涛
    蒋涛
    蝈蝈俊.net[csdn版]
    蝈蝈俊.net[joycode版]
    谭振林
    邹建
    阿不
    阿良.NET
    雨痕
    風語·深蓝
    鸟食轩(RSS)
    黄昕
    .NET 优秀网站
    .NET 官方网www.asp.net
    .NET 藏经阁 - 知识分享
    .NET开发资源精华收【不得不看】
    ASP .NET FAQ
    asp101
    aspfree
    C#开源资源
    C#开源资源大全
    C#语言在线帮助网站
    codeproject
    infragistics
    Internet Explorer 开发者资源
    iwebsms
    MSDN Web/服务
    MSDN中文
    Scott Guthrie(ASP.NET之父)
    SharePoint爱好者
    VS2005.com
    Wintellect
    www.411asp.net
    世界上最大的Open Source项目在线网站
    中国C#技术学习中心
    官方ASP.NET入门教程
    微软中文新闻组
    微软官方.NET指导站点
    最好的索引网站
    正则
    邮件发送常见问题解决方法
    Ajax链接
    AJAX载入等待图片在线生成
    bindows(RSS)
    DHTML menu4作者主页(RSS)
    Dhtmlgoodies
    Dynamicdrive
    EXT类库
    json
    Tabs
    Tabs
    Tabs
    Yahoo YUI
    大量DHTML代码
    无忧脚本 - JavaScript
    索漫
    综合开发技术网
    CSDN
    IBM中文Web 项目资源中心
    W3C技术在中国
    中国BS网
    中文C#技术站
    天新网
    天极网开发频道
    太平洋电脑网web开发
    看雪
    统一教学网
    编程爱好者
    网页设计师:web标准教程及推广,网站重构
    老猫理想
    蓝色理想
    豆豆技术网
    赛迪网
    存档
    软件项目交易
    Csdn Blog version 3.1a
    Copyright © 清清月儿