C#对鼠标的操作

C# WPF 实现鼠标固定在指定范围内运动 一.背景: 需要实现带有三个屏幕,三个屏幕分别显示窗体,但鼠标只能在主窗体中运动,不能移动到其他的两个附屏中。   二.实现: 具体实现使用的是user32.dll下的GetWindowRect(int hwnd, ref RECT lpRect)函数。 参考百度百科:https://baike.baidu.com/item/ClipCursor   ClipCursor,函数名。 阅读详情


C#对鼠标的操作

控制鼠标操作包括很多种,如限定鼠标的移动范围、设置鼠标的左右键、控制鼠标的显示和隐藏等。本节中将通过两个具体的示例来介绍有关控制鼠标操作方面的知识。 
1 .限定鼠标的移动范围 
利用 API 函数 ClipCursor 和 GetWindowRect 可以实现限定鼠标移动范围的功能。 API 函数声明如下: 
[System.Runtime.InteropServices.DllImport("user32", EntryPoint ="ClipCursor")] 
public extern static intClipCursor(ref RECT lpRect); 
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint ="GetWindowRect")] 
public extern static intGetWindowRect(int hwnd, ref RECT lpRect); 
示例控制鼠标移动 
本示例通过 API 函数 ClipCursor 和 GetWindowRect 实现了限定鼠标移动范围的功能。 
程序主要代码如下。 
单击【控制鼠标移动】按钮,鼠标只能在窗体中移动,关键代码如下: 
public struct RECT// 声明参数的值 
{ 
public int left; 
public int top; 
public int right; 
public int bottom; 
} 
public void Lock(System.Windows.Forms.Form ObjectForm) 
{ 
RECT _FormRect = new RECT(); 
GetWindowRect(ObjectForm.Handle.ToInt32(), ref _FormRect); 
ClipCursor(ref _FormRect); 
} 
单击【恢复移动】按钮,鼠标恢复移动,关键代码如下: 
public void UnLock() 
{ 
RECT _ScreenRect = new RECT(); 
_ScreenRect.top = 0; 
_ScreenRect.left = 0; 
_ScreenRect.bottom = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Bottom; 
_ScreenRect.right = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Right; 
ClipCursor(ref _ScreenRect); 
} 
2 .鼠标设置 
设置鼠标包括设置鼠标的左右键、显示与隐藏鼠标和设置双击鼠标的时间间隔等。通常使用 API 函数 SwapMouseButton 、 ShowCursor 、 SetDoubleClickTime 和 GetDoubleClickTime 对鼠标进行设置。这几个函数的声明如下: 
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint ="SwapMouseButton")] 
public extern static intSwapMouseButton(intbSwap); 
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint ="ShowCursor")] 
public extern static bool ShowCursor(bool bShow); 
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint ="SetDoubleClickTime")] 
public extern static intSetDoubleClickTime(int wCount); 
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint ="GetDoubleClickTime")] 
public extern static intGetDoubleClickTime(); 
示例鼠标设置 
本示例通过 API 函数对鼠标进行设置,通过 SwapMouseButton 函数实现隐藏鼠标光标 , ShowCursor 函数实现显示鼠标光标, SetDoubleClickTime 函数设置鼠标双击时间 ,GetDoubleClickTime 函数获取鼠标双击时间。 
程序主要代码如下。 
单击【获取鼠标双击时间】按钮,获取双击时间,并在消息框中显示,关键代码如下: 
public string DoubleClickTime_Get()




2.



怎样用C#代码实现鼠标单击(自动准确的点击到屏幕上的任何一个点)

检举  |  2010-12-10 01:17
提问者: pathfinder_zs  |  浏览次数:1647次
并请问一下鼠标点击的是逻辑坐标还是设备坐标还是窗口坐标??
谢谢!!急需
我来帮他解答
满意回答
   2010-12-10 09:42
热心网友
一、 介绍
  本文将讨论在.NET应用程序中全局系统钩子的使用。为此,我开发了一个可重用的类库并创建一个相应的示例程序(见下图)。

  你可能注意到另外的关于使用系统钩子的文章。本文与之类似但是有重要的差别。这篇文章将讨论在.NET中使用全局系统钩子,而其它文章仅讨论本地系统钩子。这些思想是类似的,但是实现要求是不同的。
  二、 背景
  如果你对Windows系统钩子的概念不熟悉,让我作一下简短的描述:
  ・一个系统钩子允许你插入一个回调函数-它拦截某些Windows消息(例如,鼠标相联系的消息)。
  ・一个本地系统钩子是一个系统钩子-它仅在指定的消息由一个单一线程处理时被调用。
  ・一个全局系统钩子是一个系统钩子-它当指定的消息被任何应用程序在整个系统上所处理时被调用。
已有若干好文章来介绍系统钩子概念。在此,不是为了重新收集这些介绍性的信息,我只是简单地请读者参考下面有关系统钩子的一些背景资料文章。如果你对系统钩子概念很熟悉,那么你能够从本文中得到你能够得到的任何东西。
  ・关于MSDN库中的钩子知识。
  ・Dino Esposito的《Cutting Edge-Windows Hooks in the .NET Framework》。
  ・Don Kackman的《在C#中应用钩子》。
  本文中我们要讨论的是扩展这个信息来创建一个全局系统钩子-它能被.NET类所使用。我们将用C#和一个DLL和非托管C++来开发一个类库-它们一起将完成这个目标。
  三、 使用代码
  在我们深入开发这个库之前,让我们快速看一下我们的目标。在本文中,我们将开发一个类库-它安装全局系统钩子并且暴露这些由钩子处理的事件,作为我们的钩子类的一个.NET事件。为了说明这个系统钩子类的用法,我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子。
  这些类库能用于创建任何类型的系统钩子,其中有两个预编译的钩子-MouseHook和KeyboardHook。我们也已经包含了这些类的特定版本,分别称为MouseHookExt和KeyboardHookExt。根据这些类所设置的模型,你能容易构建系统钩子-针对Win32 API中任何15种钩子事件类型中的任何一种。另外,这个完整的类库中还有一个编译的HTML帮助文件-它把这些类归档化。请确信你看了这个帮助文件-如果你决定在你的应用程序中使用这个库的话。
  MouseHook类的用法和生命周期相当简单。首先,我们创建MouseHook类的一个实例。

mouseHook = new MouseHook();//mouseHook是一个成员变量
  接下来,我们把MouseEvent事件绑定到一个类层次的方法上。

mouseHook.MouseEvent+=new MouseHook.MouseEventHandler(mouseHook_MouseEvent);
// ...
private void mouseHook_MouseEvent(MouseEvents mEvent, int x, int y){
 string msg =string.Format("鼠标事件::(,).",mEvent.ToString(),x,y);
 AddText(msg);//增加消息到文本框
}
  为开始收到鼠标事件,简单地安装下面的钩子即可。

mouseHook.InstallHook();
  为停止接收事件,只需简单地卸载这个钩子。

mouseHook.UninstallHook();
  你也可以调用Dispose来卸载这个钩子。
  在你的应用程序退出时,卸载这个钩子是很重要的。让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理。它甚至能够使一个或多个进程变得很不稳定。因此,请确保在你使用完钩子时一定要移去你的系统钩子。我们确定在我们的示例应用程序会移去该系统钩子-通过在Form的Dispose方法中添加一个Dispose调用。

protected override void Dispose(bool disposing) {
 if (disposing) {
  if (mouseHook != null) {
   mouseHook.Dispose();
   mouseHook = null;
  }
  // ...
 }
}
  使用该类库的情况就是如此。该类库中有两个系统钩子类并且相当容易扩充。
  四、 构建库
  这个库共有两个主要组件。第一部分是一个C#类库-你可以直接使用于你的应用程序中。该类库,反过来,在内部使用一个非托管的C++ DLL来直接管理系统钩子。我们将首先讨论开发该C++部分。接下来,我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类。就象我们讨论C++/C#交互一样,我们将特别注意C++方法和数据类型是怎样映射到.NET方法和数据类型的。
  你可能想知道为什么我们需要两个库,特别是一个非托管的C++ DLL。你还可能注意到在本文的背景一节中提到的两篇参考文章,其中并没有使用任何非托管的代码。为此,我的回答是,"对!这正是我写这篇文章的原因"。当你思考系统钩子是怎样实际地实现它们的功能时,我们需要非托管的代码是十分重要的。为了使一个全局的系统钩子能够工作,Windows把你的DLL插入到每个正在运行的进程的进程空间中。既然大多数进程不是.NET进程,所以,它们不能直接执行.NET装配集。我们需要一种非托管的代码代理- Windows可以把它插入到所有将要被钩住的进程中。
  首先是提供一种机制来把一个.NET代理传递到我们的C++库。这样,我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc)。

int SetUserHookCallback(HookProc userProc, UINT hookID)
typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l)
  SetUserHookCallback的第二个参数是钩子类型-这个函数指针将使用它。现在,我们必须用C#来定义相应的方法和代理以使用这段代码。下面是我们怎样把它映射到C#。

private static extern SetCallBackResults
SetUserHookCallback(HookProcessedHandler hookCallback, HookTypes hookType)
protected delegate void HookProcessedHandler(int code, UIntPtr wparam, IntPtr lparam)
public enum HookTypes {
 JournalRecord = 0,
 JournalPlayback = 1,
 // ...
 KeyboardLL = 13,
 MouseLL = 14
};
  首先,我们使用DllImport属性导入SetUserHookCallback函数,作为我们的抽象基钩子类SystemHook的一个静态的外部的方法。为此,我们必须映射一些外部数据类型。首先,我们必须创建一个代理作为我们的函数指针。这是通过定义上面的HookProcessHandler 来实现的。我们需要一个函数,它的C++签名为(int,WPARAM,LPARAM)。在Visual Studio .NET C++编译器中,int与C#中是一样的。也就是说,在C++与C#中int就是Int32。事情并不总是这样。一些编译器把C++ int作为Int16对待。我们坚持使用Visual Studio .NET C++编译器来实现这个工程,因此,我们不必担心编译器差别所带来的另外的定义。
  接下来,我们需要用C#传递WPARAM和LPARAM值。这些确实是指针,它们分别指向C++的UINT和LONG值。用C#来说,它们是指向uint和int的指针。如果你还不确定什么是WPARAM,你可以通过在C++代码中单击右键来查询它,并且选择"Go to definition"。这将会引导你到在windef.h中的定义。

//从windef.h:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
  因此,我们选择System.UIntPtr和System.IntPtr作为我们的变量类型-它们分别相应于WPARAM和LPARAM类型,当它们使用在C#中时。
现在,让我们看一下钩子基类是怎样使用这些导入的方法来传递一个回叫函数(代理)到C++中-它允许C++库直接调用你的系统钩子类的实例。首先,在构造器中,SystemHook类创建一个到私有方法InternalHookCallback的代理-它匹配HookProcessedHandler代理签名。然后,它把这个代理和它的HookType传递到C++库以使用SetUserHookCallback方法来注册该回叫函数,如上面所讨论的。下面是其代码实现:

public SystemHook(HookTypes type){
 _type = type;
 _processHandler = new HookProcessedHandler(InternalHookCallback);
 SetUserHookCallback(_processHandler, _type);
}
  InternalHookCallback的实现相当简单。InternalHookCallback在用一个catch-all try/catch块包装它的同时仅传递到抽象方法HookCallback的调用。这将简化在派生类中的实现并且保护C++代码。记住,一旦一切都准备妥当,这个C++钩子就会直接调用这个方法。

[MethodImpl(MethodImplOptions.NoInlining)]
private void InternalHookCallback(int code, UIntPtr wparam, IntPtr lparam){
try 
catch {}
}
  我们已增加了一个方法实现属性-它告诉编译器不要内联这个方法。这不是可选的。至少,在我添加try/catch之前是需要的。看起来,由于某些原因,编译器在试图内联这个方法-这将给包装它的代理带来各种麻烦。然后,C++层将回叫,而该应用程序将会崩溃。
  现在,让我们看一下一个派生类是怎样用一个特定的HookType来接收和处理钩子事件。下面是虚拟的MouseHook类的HookCallback方法实现:

protected override void HookCallback(int code, UIntPtr wparam, IntPtr lparam){
 if (MouseEvent == null) 
  int x = 0, y = 0;
  MouseEvents mEvent = (MouseEvents)wparam.ToUInt32();
  switch(mEvent) {
   case MouseEvents.LeftButtonDown:
    GetMousePosition(wparam, lparam, ref x, ref y);
    break;
   // ...
  }
 MouseEvent(mEvent, new Point(x, y));
}
  首先,注意这个类定义一个事件MouseEvent-该类在收到一个钩子事件时激发这个事件。这个类在激发它的事件之前,把数据从WPARAM和 LPARAM类型转换成.NET中有意义的鼠标事件数据。这样可以使得类的消费者免于担心解释这些数据结构。这个类使用导入的 GetMousePosition函数-我们在C++ DLL中定义的用来转换这些值。为此,请看下面几段的讨论。
  在这个方法中,我们检查是否有人在听这一个事件。如果没有,不必继续处理这一事件。然后,我们把WPARAM转换成一个MouseEvents枚举类型。我们已小心地构造了MouseEvents枚举来准确匹配它们在C ++中相应的常数。这允许我们简单地把指针的值转换成枚举类型。但是要注意,这种转换即使在WPARAM的值不匹配一个枚举值的情况下也会成功。 mEvent的值将仅是未定义的(不是null,只是不在枚举值范围之内)。为此,请详细分析System.Enum.IsDefined方法。
  接下来,在确定我们收到的事件类型后,该类激活这个事件,并且通知消费者鼠标事件的类型及在该事件过程中鼠标的位置。
  最后注意,有关转换WPARAM和LPARAM值:对于每个类型的事件,这些变量的值和意思是不同的。因此,在每一种钩子类型中,我们必须区别地解释这些值。我选择用C++实现这种转换,而不是尽量用C#来模仿复杂的C++结构和指针。例如,前面的类就使用了一个叫作GetMousePosition的 C++函数。下面是C++ DLL中的这个方法:

bool GetMousePosition(WPARAM wparam, LPARAM lparam, int amp; x, int amp; y) {
 MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam;
 x = pMouseStruct->pt.x;
 y = pMouseStruct->pt.y;
 return true;
}
  不是尽量映射MOUSEHOOKSTRUCT结构指针到C#,我们简单地暂时把它回传到C++层以提取我们需要的值。注意,因为我们需要从这个调用中返回一些值,我们把我们的整数作为参考变量传递。这直接映射到C#中的int*。但是,我们可以重载这个行为,通过选择正确的签名来导入这个方法。

private static extern bool InternalGetMousePosition(UIntPtr wparam,IntPtr lparam, ref int x, ref int y)
  通过把integer参数定义为ref int,我们得到通过C++参照传递给我们的值。如果我们想要的话,我们还可以使用out int。
  五、 限制
  一些钩子类型并不适合实现全局钩子。我当前正在考虑解决办法-它将允许使用受限制的钩子类型。到目前为止,不要把这些类型添加回该库中,因为它们将导致应用程序的失败(经常是系统范围的灾难性失败)。下一节将集中讨论这些限制背后的原因和解决办法。

HookTypes.CallWindowProcedure
HookTypes.CallWindowProret
HookTypes.ComputerBasedTraining
HookTypes.Debug
HookTypes.ForegroundIdle
HookTypes.JournalRecord
HookTypes.JournalPlayback
HookTypes.GetMessage
HookTypes.SystemMessageFilter
  六、 两种类型的钩子
  在本节中,我将尽量解释为什么一些钩子类型被限制在一定的范畴内而另外一些则不受限制。如果我使用有点偏差术语的话,请原谅我。我还没有找到任何有关这部分题目的文档,因此,我编造了我自己的词汇。另外,如果你认为我根本就不对,请告诉我好了。
  当Windows调用传递到SetWindowsHookEx()的回调函数时它们会因不同类型的钩子而被区别调用。基本上有两种情况:切换执行上下文的钩子和不切换执行上下文的钩子。用另一种方式说,也就是,在放钩子的应用程序进程空间执行钩子回调函数的情况和在被钩住的应用程序进程空间执行钩子回调函数的情况。
  钩子类型例如鼠标和键盘钩子都是在被Windows调用之前切换上下文的。整个过程大致如下:
  1. 应用程序X拥有焦点并执行。
  2. 用户按下一个键。
  3. Windows从应用程序X接管上下文并把执行上下文切换到放钩子的应用程序。
  4. Windows用放钩子的应用程序进程空间中的键消息参数调用钩子回调函数。
  5. Windows从放钩子的应用程序接管上下文并把执行上下文切换回应用程序X。
  6. Windows把消息放进应用程序X的消息排队。
  7. 稍微一会儿之后,当应用程序X执行时,它从自己的消息排队中取出消息并且调用它的内部按键(或松开或按下)处理器。
  8. 应用程序X继续执行...
  例如CBT钩子(window创建,等等。)的钩子类型并不切换上下文。对于这些类型的钩子,过程大致如下:
  1. 应用程序X拥有焦点并执行。
  2. 应用程序X创建一个窗口。
  3. Windows用在应用程序X进程空间中的CBT事件消息参数调用钩子回调函数。
  4. 应用程序X继续执行...
  这应该说明了为什么某种类型的钩子能够用这个库结构工作而一些却不能。记住,这正是该库要做的。在上面第4步和第3步之后,分别插入下列步骤:
  1. Windows调用钩子回调函数。
  2. 目标回调函数在非托管的DLL中执行。
  3. 目标回调函数查找它的相应托管的调用代理。
  4. 托管代理被以适当的参数执行。
  5. 目标回调函数返回并执行相应于指定消息的钩子处理。
  第三步和第四步因非切换钩子类型而注定失败。第三步将失败,因为相应的托管回调函数不会为该应用程序而设置。记住,这个DLL使用全局变量来跟踪这些托管代理并且该钩子DLL被加载到每一个进程空间。但是这个值仅在放钩子的应用程序进程空间中设置。对于另外其它情况,它们全部为null。
  Tim Sylvester在他的《Other hook types》一文中指出,使用一个共享内存区段将会解决这个问题。这是真实的,但是也如Tim所指出的,那些托管代理地址对于除了放钩子的应用程序之外的任何进程是无意义的。这意味着,它们是无意义的并且不能在回调函数的执行过程中调用。那样会有麻烦的。
  因此,为了把这些回调函数使用于不执行上下文切换的钩子类型,你需要某种进程间的通讯。
  我已经试验过这种思想-使用非托管的DLL钩子回调函数中的进程外COM对象进行IPC。如果你能使这种方法工作,我将很高兴了解到这点。至于我的尝试,结果并不理想。基本原因是很难针对各种进程和它们的线程(CoInitialize(NULL))而正确地初始化COM单元。这是一个在你可以使用 COM对象之前的基本要求。
  我不怀疑,一定有办法来解决这个问题。但是我还没有试用过它们,因为我认为它们仅有有限的用处。例如,CBT钩子可以让你取消一个窗口创建,如果你希望的话。可以想像,为使这能够工作将会发生什么。
  1. 钩子回调函数开始执行。
  2. 调用非托管的钩子DLL中的相应的钩子回调函数。
  3. 执行必须被路由回到主钩子应用程序。
  4. 该应用程序必须决定是否允许这一创建。
  5. 调用必须被路由回仍旧在运行中的钩子回调函数。
  6. 在非托管的钩子DLL中的钩子回调函数从主钩子应用程序接收到要采取的行动。
  7. 在非托管的钩子DLL中的钩子回调函数针对CBT钩子调用采取适当的行动。
  8. 完成钩子回调函数的执行。
  这不是不可能的,但是不算好的。我希望这会消除在该库中的围绕被允许的和受限制的钩子类型所带来的神秘。
  七、 其它
  ・库文档:我们已经包含了有关ManagedHooks类库的比较完整的代码文档。当以"Documentation"构建配置进行编译时,这被经由Visual Studio.NET转换成标准帮助XML。最后,我们已使用NDoc来把它转换成编译的HTML帮助(CHM)。你可以看这个帮助文件,只需简单地在该方案的解决方案资源管理器中点击Hooks.chm文件或通过查找与该文相关的可下载的ZIP文件。
  ・增强的智能感知:如果你不熟悉Visual Studio.NET怎样使用编译的XML文件(pre-NDoc output)来为参考库的工程增强智能感知,那么让我简单地介绍一下。如果你决定在你的应用程序中使用这个类库,你可以考虑复制该库的一个稳定构建版本到你想参考它的位置。同时,还要把XML文档文件 (SystemHooks\ManagedHooks\bin\Debug\Kennedy.ManagedHooks.xml)复制到相同的位置。当你添加一个参考到该库时,Visual Studio.NET将自动地读该文件并使用它来添加智能感知文档。这是很有用的,特别是对于象这样的第三方库。
  ・单元测试:我相信,所有的库都应有与之相应的单元测试。既然我是一家公司(主要负责针对.NET环境软件的单元测试)的合伙人和软件工程师,任何人不会对此感到惊讶。因而,你将会在名为ManagedHooksTests的解决方案中找到一个单元测试工程。为了运行该单元测试,你需要下载和安装 HarnessIt-这个下载是我们的商业单元测试软件的一个自由的试用版本。在该单元测试中,我对这给予了特殊的注意-在此处,方法的无效参数可能导致 C++内存异常的发生。尽管这个库是相当简单的,但该单元测试确实能够帮助我在一些更为微妙的情况下发现一些错误。
  ・非托管的/托管的调试:有关混合解决方案(例如,本文的托管的和非托管的代码)最为技巧的地方之一是调试问题。如果你想单步调试该C++代码或在C++代码中设置断点,你必须启动非托管的调试。这是一个Visual Studio.NET中的工程设置。注意,你可以非常顺利地单步调试托管的和非托管的层,但是,在调试过程中,非托管的调试确实严重地减慢应用程序的装载时间和执行速度。
  八、 最后警告
  很明显,系统钩子相当有力量;然而,使用这种力量应该是有责任性的。在系统钩子出了问题时,它们不仅仅垮掉你的应用程序。它们可以垮掉在你的当前系统中运行的每个应用程序。但是到这种程度的可能性一般是很小的。尽管如此,在使用系统钩子时,你还是需要再三检查你的代码。
  我发现了一项可以用来开发应用程序的有用的技术-它使用系统钩子来在微软的虚拟PC上安装你的喜爱的开发操作系统的一个拷贝和Visual Studio.NET。然后,你就可以在此虚拟的环境中开发你的应用程序。用这种方式,当你的钩子应用程序出现错误时,它们将仅退出你的操作系统的虚拟实例而不是你的真正的操作系统。我已经不得不重启动我的真正的OS-在这个虚拟OS由于一个钩子错误崩溃时,但是这并不经常。
2
|  评论








怎样用C#代码实现鼠标单击(自动准确的点击到屏幕上的任何一个点)

检举  |  2010-12-10 01:17
提问者: pathfinder_zs  |  浏览次数:1647次
并请问一下鼠标点击的是逻辑坐标还是设备坐标还是窗口坐标??
谢谢!!急需
我来帮他解答
满意回答
   2010-12-10 09:42
热心网友
一、 介绍
  本文将讨论在.NET应用程序中全局系统钩子的使用。为此,我开发了一个可重用的类库并创建一个相应的示例程序(见下图)。

  你可能注意到另外的关于使用系统钩子的文章。本文与之类似但是有重要的差别。这篇文章将讨论在.NET中使用全局系统钩子,而其它文章仅讨论本地系统钩子。这些思想是类似的,但是实现要求是不同的。
  二、 背景
  如果你对Windows系统钩子的概念不熟悉,让我作一下简短的描述:
  ・一个系统钩子允许你插入一个回调函数-它拦截某些Windows消息(例如,鼠标相联系的消息)。
  ・一个本地系统钩子是一个系统钩子-它仅在指定的消息由一个单一线程处理时被调用。
  ・一个全局系统钩子是一个系统钩子-它当指定的消息被任何应用程序在整个系统上所处理时被调用。
已有若干好文章来介绍系统钩子概念。在此,不是为了重新收集这些介绍性的信息,我只是简单地请读者参考下面有关系统钩子的一些背景资料文章。如果你对系统钩子概念很熟悉,那么你能够从本文中得到你能够得到的任何东西。
  ・关于MSDN库中的钩子知识。
  ・Dino Esposito的《Cutting Edge-Windows Hooks in the .NET Framework》。
  ・Don Kackman的《在C#中应用钩子》。
  本文中我们要讨论的是扩展这个信息来创建一个全局系统钩子-它能被.NET类所使用。我们将用C#和一个DLL和非托管C++来开发一个类库-它们一起将完成这个目标。
  三、 使用代码
  在我们深入开发这个库之前,让我们快速看一下我们的目标。在本文中,我们将开发一个类库-它安装全局系统钩子并且暴露这些由钩子处理的事件,作为我们的钩子类的一个.NET事件。为了说明这个系统钩子类的用法,我们将在一个用C#编写的Windows表单应用程序中创建一个鼠标事件钩子和一个键盘事件钩子。
  这些类库能用于创建任何类型的系统钩子,其中有两个预编译的钩子-MouseHook和KeyboardHook。我们也已经包含了这些类的特定版本,分别称为MouseHookExt和KeyboardHookExt。根据这些类所设置的模型,你能容易构建系统钩子-针对Win32 API中任何15种钩子事件类型中的任何一种。另外,这个完整的类库中还有一个编译的HTML帮助文件-它把这些类归档化。请确信你看了这个帮助文件-如果你决定在你的应用程序中使用这个库的话。
  MouseHook类的用法和生命周期相当简单。首先,我们创建MouseHook类的一个实例。

mouseHook = new MouseHook();//mouseHook是一个成员变量
  接下来,我们把MouseEvent事件绑定到一个类层次的方法上。

mouseHook.MouseEvent+=new MouseHook.MouseEventHandler(mouseHook_MouseEvent);
// ...
private void mouseHook_MouseEvent(MouseEvents mEvent, int x, int y){
 string msg =string.Format("鼠标事件::(,).",mEvent.ToString(),x,y);
 AddText(msg);//增加消息到文本框
}
  为开始收到鼠标事件,简单地安装下面的钩子即可。

mouseHook.InstallHook();
  为停止接收事件,只需简单地卸载这个钩子。

mouseHook.UninstallHook();
  你也可以调用Dispose来卸载这个钩子。
  在你的应用程序退出时,卸载这个钩子是很重要的。让系统钩子一直安装着将减慢系统中的所有的应用程序的消息处理。它甚至能够使一个或多个进程变得很不稳定。因此,请确保在你使用完钩子时一定要移去你的系统钩子。我们确定在我们的示例应用程序会移去该系统钩子-通过在Form的Dispose方法中添加一个Dispose调用。

protected override void Dispose(bool disposing) {
 if (disposing) {
  if (mouseHook != null) {
   mouseHook.Dispose();
   mouseHook = null;
  }
  // ...
 }
}
  使用该类库的情况就是如此。该类库中有两个系统钩子类并且相当容易扩充。
  四、 构建库
  这个库共有两个主要组件。第一部分是一个C#类库-你可以直接使用于你的应用程序中。该类库,反过来,在内部使用一个非托管的C++ DLL来直接管理系统钩子。我们将首先讨论开发该C++部分。接下来,我们将讨论怎么在C#中使用这个库来构建一个通用的钩子类。就象我们讨论C++/C#交互一样,我们将特别注意C++方法和数据类型是怎样映射到.NET方法和数据类型的。
  你可能想知道为什么我们需要两个库,特别是一个非托管的C++ DLL。你还可能注意到在本文的背景一节中提到的两篇参考文章,其中并没有使用任何非托管的代码。为此,我的回答是,"对!这正是我写这篇文章的原因"。当你思考系统钩子是怎样实际地实现它们的功能时,我们需要非托管的代码是十分重要的。为了使一个全局的系统钩子能够工作,Windows把你的DLL插入到每个正在运行的进程的进程空间中。既然大多数进程不是.NET进程,所以,它们不能直接执行.NET装配集。我们需要一种非托管的代码代理- Windows可以把它插入到所有将要被钩住的进程中。
  首先是提供一种机制来把一个.NET代理传递到我们的C++库。这样,我们用C++语言定义下列函数(SetUserHookCallback)和函数指针(HookProc)。

int SetUserHookCallback(HookProc userProc, UINT hookID)
typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l)
  SetUserHookCallback的第二个参数是钩子类型-这个函数指针将使用它。现在,我们必须用C#来定义相应的方法和代理以使用这段代码。下面是我们怎样把它映射到C#。

private static extern SetCallBackResults
SetUserHookCallback(HookProcessedHandler hookCallback, HookTypes hookType)
protected delegate void HookProcessedHandler(int code, UIntPtr wparam, IntPtr lparam)
public enum HookTypes {
 JournalRecord = 0,
 JournalPlayback = 1,
 // ...
 KeyboardLL = 13,
 MouseLL = 14
};
  首先,我们使用DllImport属性导入SetUserHookCallback函数,作为我们的抽象基钩子类SystemHook的一个静态的外部的方法。为此,我们必须映射一些外部数据类型。首先,我们必须创建一个代理作为我们的函数指针。这是通过定义上面的HookProcessHandler 来实现的。我们需要一个函数,它的C++签名为(int,WPARAM,LPARAM)。在Visual Studio .NET C++编译器中,int与C#中是一样的。也就是说,在C++与C#中int就是Int32。事情并不总是这样。一些编译器把C++ int作为Int16对待。我们坚持使用Visual Studio .NET C++编译器来实现这个工程,因此,我们不必担心编译器差别所带来的另外的定义。
  接下来,我们需要用C#传递WPARAM和LPARAM值。这些确实是指针,它们分别指向C++的UINT和LONG值。用C#来说,它们是指向uint和int的指针。如果你还不确定什么是WPARAM,你可以通过在C++代码中单击右键来查询它,并且选择"Go to definition"。这将会引导你到在windef.h中的定义。

//从windef.h:
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
  因此,我们选择System.UIntPtr和System.IntPtr作为我们的变量类型-它们分别相应于WPARAM和LPARAM类型,当它们使用在C#中时。
现在,让我们看一下钩子基类是怎样使用这些导入的方法来传递一个回叫函数(代理)到C++中-它允许C++库直接调用你的系统钩子类的实例。首先,在构造器中,SystemHook类创建一个到私有方法InternalHookCallback的代理-它匹配HookProcessedHandler代理签名。然后,它把这个代理和它的HookType传递到C++库以使用SetUserHookCallback方法来注册该回叫函数,如上面所讨论的。下面是其代码实现:

public SystemHook(HookTypes type){
 _type = type;
 _processHandler = new HookProcessedHandler(InternalHookCallback);
 SetUserHookCallback(_processHandler, _type);
}
  InternalHookCallback的实现相当简单。InternalHookCallback在用一个catch-all try/catch块包装它的同时仅传递到抽象方法HookCallback的调用。这将简化在派生类中的实现并且保护C++代码。记住,一旦一切都准备妥当,这个C++钩子就会直接调用这个方法。

[MethodImpl(MethodImplOptions.NoInlining)]
private void InternalHookCallback(int code, UIntPtr wparam, IntPtr lparam){
try 
catch {}
}
  我们已增加了一个方法实现属性-它告诉编译器不要内联这个方法。这不是可选的。至少,在我添加try/catch之前是需要的。看起来,由于某些原因,编译器在试图内联这个方法-这将给包装它的代理带来各种麻烦。然后,C++层将回叫,而该应用程序将会崩溃。
  现在,让我们看一下一个派生类是怎样用一个特定的HookType来接收和处理钩子事件。下面是虚拟的MouseHook类的HookCallback方法实现:

protected override void HookCallback(int code, UIntPtr wparam, IntPtr lparam){
 if (MouseEvent == null) 
  int x = 0, y = 0;
  MouseEvents mEvent = (MouseEvents)wparam.ToUInt32();
  switch(mEvent) {
   case MouseEvents.LeftButtonDown:
    GetMousePosition(wparam, lparam, ref x, ref y);
    break;
   // ...
  }
 MouseEvent(mEvent, new Point(x, y));
}
  首先,注意这个类定义一个事件MouseEvent-该类在收到一个钩子事件时激发这个事件。这个类在激发它的事件之前,把数据从WPARAM和 LPARAM类型转换成.NET中有意义的鼠标事件数据。这样可以使得类的消费者免于担心解释这些数据结构。这个类使用导入的 GetMousePosition函数-我们在C++ DLL中定义的用来转换这些值。为此,请看下面几段的讨论。
  在这个方法中,我们检查是否有人在听这一个事件。如果没有,不必继续处理这一事件。然后,我们把WPARAM转换成一个MouseEvents枚举类型。我们已小心地构造了MouseEvents枚举来准确匹配它们在C ++中相应的常数。这允许我们简单地把指针的值转换成枚举类型。但是要注意,这种转换即使在WPARAM的值不匹配一个枚举值的情况下也会成功。 mEvent的值将仅是未定义的(不是null,只是不在枚举值范围之内)。为此,请详细分析System.Enum.IsDefined方法。
  接下来,在确定我们收到的事件类型后,该类激活这个事件,并且通知消费者鼠标事件的类型及在该事件过程中鼠标的位置。
  最后注意,有关转换WPARAM和LPARAM值:对于每个类型的事件,这些变量的值和意思是不同的。因此,在每一种钩子类型中,我们必须区别地解释这些值。我选择用C++实现这种转换,而不是尽量用C#来模仿复杂的C++结构和指针。例如,前面的类就使用了一个叫作GetMousePosition的 C++函数。下面是C++ DLL中的这个方法:

bool GetMousePosition(WPARAM wparam, LPARAM lparam, int amp; x, int amp; y) {
 MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lparam;
 x = pMouseStruct->pt.x;
 y = pMouseStruct->pt.y;
 return true;
}
  不是尽量映射MOUSEHOOKSTRUCT结构指针到C#,我们简单地暂时把它回传到C++层以提取我们需要的值。注意,因为我们需要从这个调用中返回一些值,我们把我们的整数作为参考变量传递。这直接映射到C#中的int*。但是,我们可以重载这个行为,通过选择正确的签名来导入这个方法。

private static extern bool InternalGetMousePosition(UIntPtr wparam,IntPtr lparam, ref int x, ref int y)
  通过把integer参数定义为ref int,我们得到通过C++参照传递给我们的值。如果我们想要的话,我们还可以使用out int。
  五、 限制
  一些钩子类型并不适合实现全局钩子。我当前正在考虑解决办法-它将允许使用受限制的钩子类型。到目前为止,不要把这些类型添加回该库中,因为它们将导致应用程序的失败(经常是系统范围的灾难性失败)。下一节将集中讨论这些限制背后的原因和解决办法。

HookTypes.CallWindowProcedure
HookTypes.CallWindowProret
HookTypes.ComputerBasedTraining
HookTypes.Debug
HookTypes.ForegroundIdle
HookTypes.JournalRecord
HookTypes.JournalPlayback
HookTypes.GetMessage
HookTypes.SystemMessageFilter
  六、 两种类型的钩子
  在本节中,我将尽量解释为什么一些钩子类型被限制在一定的范畴内而另外一些则不受限制。如果我使用有点偏差术语的话,请原谅我。我还没有找到任何有关这部分题目的文档,因此,我编造了我自己的词汇。另外,如果你认为我根本就不对,请告诉我好了。
  当Windows调用传递到SetWindowsHookEx()的回调函数时它们会因不同类型的钩子而被区别调用。基本上有两种情况:切换执行上下文的钩子和不切换执行上下文的钩子。用另一种方式说,也就是,在放钩子的应用程序进程空间执行钩子回调函数的情况和在被钩住的应用程序进程空间执行钩子回调函数的情况。
  钩子类型例如鼠标和键盘钩子都是在被Windows调用之前切换上下文的。整个过程大致如下:
  1. 应用程序X拥有焦点并执行。
  2. 用户按下一个键。
  3. Windows从应用程序X接管上下文并把执行上下文切换到放钩子的应用程序。
  4. Windows用放钩子的应用程序进程空间中的键消息参数调用钩子回调函数。
  5. Windows从放钩子的应用程序接管上下文并把执行上下文切换回应用程序X。
  6. Windows把消息放进应用程序X的消息排队。
  7. 稍微一会儿之后,当应用程序X执行时,它从自己的消息排队中取出消息并且调用它的内部按键(或松开或按下)处理器。
  8. 应用程序X继续执行...
  例如CBT钩子(window创建,等等。)的钩子类型并不切换上下文。对于这些类型的钩子,过程大致如下:
  1. 应用程序X拥有焦点并执行。
  2. 应用程序X创建一个窗口。
  3. Windows用在应用程序X进程空间中的CBT事件消息参数调用钩子回调函数。
  4. 应用程序X继续执行...
  这应该说明了为什么某种类型的钩子能够用这个库结构工作而一些却不能。记住,这正是该库要做的。在上面第4步和第3步之后,分别插入下列步骤:
  1. Windows调用钩子回调函数。
  2. 目标回调函数在非托管的DLL中执行。
  3. 目标回调函数查找它的相应托管的调用代理。
  4. 托管代理被以适当的参数执行。
  5. 目标回调函数返回并执行相应于指定消息的钩子处理。
  第三步和第四步因非切换钩子类型而注定失败。第三步将失败,因为相应的托管回调函数不会为该应用程序而设置。记住,这个DLL使用全局变量来跟踪这些托管代理并且该钩子DLL被加载到每一个进程空间。但是这个值仅在放钩子的应用程序进程空间中设置。对于另外其它情况,它们全部为null。
  Tim Sylvester在他的《Other hook types》一文中指出,使用一个共享内存区段将会解决这个问题。这是真实的,但是也如Tim所指出的,那些托管代理地址对于除了放钩子的应用程序之外的任何进程是无意义的。这意味着,它们是无意义的并且不能在回调函数的执行过程中调用。那样会有麻烦的。
  因此,为了把这些回调函数使用于不执行上下文切换的钩子类型,你需要某种进程间的通讯。
  我已经试验过这种思想-使用非托管的DLL钩子回调函数中的进程外COM对象进行IPC。如果你能使这种方法工作,我将很高兴了解到这点。至于我的尝试,结果并不理想。基本原因是很难针对各种进程和它们的线程(CoInitialize(NULL))而正确地初始化COM单元。这是一个在你可以使用 COM对象之前的基本要求。
  我不怀疑,一定有办法来解决这个问题。但是我还没有试用过它们,因为我认为它们仅有有限的用处。例如,CBT钩子可以让你取消一个窗口创建,如果你希望的话。可以想像,为使这能够工作将会发生什么。
  1. 钩子回调函数开始执行。
  2. 调用非托管的钩子DLL中的相应的钩子回调函数。
  3. 执行必须被路由回到主钩子应用程序。
  4. 该应用程序必须决定是否允许这一创建。
  5. 调用必须被路由回仍旧在运行中的钩子回调函数。
  6. 在非托管的钩子DLL中的钩子回调函数从主钩子应用程序接收到要采取的行动。
  7. 在非托管的钩子DLL中的钩子回调函数针对CBT钩子调用采取适当的行动。
  8. 完成钩子回调函数的执行。
  这不是不可能的,但是不算好的。我希望这会消除在该库中的围绕被允许的和受限制的钩子类型所带来的神秘。
  七、 其它
  ・库文档:我们已经包含了有关ManagedHooks类库的比较完整的代码文档。当以"Documentation"构建配置进行编译时,这被经由Visual Studio.NET转换成标准帮助XML。最后,我们已使用NDoc来把它转换成编译的HTML帮助(CHM)。你可以看这个帮助文件,只需简单地在该方案的解决方案资源管理器中点击Hooks.chm文件或通过查找与该文相关的可下载的ZIP文件。
  ・增强的智能感知:如果你不熟悉Visual Studio.NET怎样使用编译的XML文件(pre-NDoc output)来为参考库的工程增强智能感知,那么让我简单地介绍一下。如果你决定在你的应用程序中使用这个类库,你可以考虑复制该库的一个稳定构建版本到你想参考它的位置。同时,还要把XML文档文件 (SystemHooks\ManagedHooks\bin\Debug\Kennedy.ManagedHooks.xml)复制到相同的位置。当你添加一个参考到该库时,Visual Studio.NET将自动地读该文件并使用它来添加智能感知文档。这是很有用的,特别是对于象这样的第三方库。
  ・单元测试:我相信,所有的库都应有与之相应的单元测试。既然我是一家公司(主要负责针对.NET环境软件的单元测试)的合伙人和软件工程师,任何人不会对此感到惊讶。因而,你将会在名为ManagedHooksTests的解决方案中找到一个单元测试工程。为了运行该单元测试,你需要下载和安装 HarnessIt-这个下载是我们的商业单元测试软件的一个自由的试用版本。在该单元测试中,我对这给予了特殊的注意-在此处,方法的无效参数可能导致 C++内存异常的发生。尽管这个库是相当简单的,但该单元测试确实能够帮助我在一些更为微妙的情况下发现一些错误。
  ・非托管的/托管的调试:有关混合解决方案(例如,本文的托管的和非托管的代码)最为技巧的地方之一是调试问题。如果你想单步调试该C++代码或在C++代码中设置断点,你必须启动非托管的调试。这是一个Visual Studio.NET中的工程设置。注意,你可以非常顺利地单步调试托管的和非托管的层,但是,在调试过程中,非托管的调试确实严重地减慢应用程序的装载时间和执行速度。
  八、 最后警告
  很明显,系统钩子相当有力量;然而,使用这种力量应该是有责任性的。在系统钩子出了问题时,它们不仅仅垮掉你的应用程序。它们可以垮掉在你的当前系统中运行的每个应用程序。但是到这种程度的可能性一般是很小的。尽管如此,在使用系统钩子时,你还是需要再三检查你的代码。
  我发现了一项可以用来开发应用程序的有用的技术-它使用系统钩子来在微软的虚拟PC上安装你的喜爱的开发操作系统的一个拷贝和Visual Studio.NET。然后,你就可以在此虚拟的环境中开发你的应用程序。用这种方式,当你的钩子应用程序出现错误时,它们将仅退出你的操作系统的虚拟实例而不是你的真正的操作系统。我已经不得不重启动我的真正的OS-在这个虚拟OS由于一个钩子错误崩溃时,但是这并不经常。
2
|  评论
c#鼠标移动控制 通过调用windows系统自带user32.dll库中方法进行鼠标移动控制。 阅读详情

相关推荐

C#实现限制鼠标在一个矩形或者圆形区域内工作

正常情况下,鼠标的移动范围是整个屏幕,但有时需要鼠标在某一区域内移动,这个区域可以是矩形也可以是圆形

灵犀木白的博客 2183

C# ClipCursor

  public   Rectangle   rect;         [DllImport("user32.dll",EntryPoint="clipcursor")]     private   static   extern   bool   clipcursor(Rectangle   lpRect)     然后在你的绘制函数树中         Rectangle   rect=

旅途 2899

C#-鼠标操作

获取当前鼠标位置 int xx = Control.MousePosition.X; int yy = Control.MousePosition.Y; #region 鼠标API /// /// 鼠标移动 /// /// 目标x坐标 /// 目标y坐标 ///

天使也掉毛 663

C#鼠标控制

【代码】C#鼠标控制。

qq_22868237的博客 547

Arduino--土壤湿度传感器使用(电阻式)

最近买了一个土壤湿度检测传感器,实物图是这样的: 我买这个模块是想要得到土壤湿度的模拟量。但我买的时候忘了买左边的蓝色模块,我开始以为这个模块是有运放功能的,但实际它是一个电压比较器和一个分压电路。 其模块的接线如图: 该模块的四线是带模拟量输出的,三线的只输出一个到达阈值的标志量。该模块的原理图如下: 该模块的测试原理为:把土壤当成一个可变电阻,随着土壤含水量的增加,土壤电阻减小。而该传感器其实就是两个电极,用来接土壤这个可变电阻。一般湿度的土壤电阻大概在几百K左右,其串连的分压电阻应该在这个数量级。

weixin_41866783的博客 1万+

MTK Linux DRM分析(八)- KMS drm_crtc.c

CRTC 在 Linux DRM 子系统中是显示控制的核心,负责时序生成、模式设置和管线的调度。理解其工作原理和 API 对于进行底层图形开发、调试显示问题或 simply understanding how your graphics stack works 都至关重要。

iTom1900 1349

C# 监听鼠标操作

通过这几篇内容,我想我们可以整合一下,做一个简单的操作录制功能,用来解决一下日常的繁琐切循环的操作,这个功能之前有发过一个简单的版本,但不是通过HOOK去实现的,而是让用户自己手动录制,再去执行。使用HOOK的话,直接监听一遍用户的操作,记录相应的动作即可,同时可操作性也有很大提高(emmmm,我觉得回头有时间我自己先封装下,可能用途还不小,同时想起之前写的关键字查询的工具,以为只是偶尔之需,万万没想到它在我生活、工作中也帮了我很多。HOOK的工具类可参考前面的文章,这里不赘述,贴下需要更改的代码。

qq_27410185的博客 7387

Vmware虚拟机一打开就蓝屏解决方法

Vmware虚拟机一打开就蓝屏解决方法 问题: 一打开Vmware虚拟机就蓝屏,如下图所示: 解决方法1: 启用和关闭windows功能(对话框)——>虚拟机平台(选项打对勾,默认没勾选)——>确定后重启——>再进应该就好了。 解决方法2: ①.查看电脑中的Hyper-V服务是否关闭 1.打开控制面板-程序-程序和功能 2.双击启用或关闭Windows功能 3.把Hyper-V前面的勾去掉 如果后期发下没有反应,或者电脑本身Hyper-V的服务没有打开,可以先打开在关闭,试

m0_55901666的博客 26万+

C#实现对鼠标的操作

C#实现对鼠标的操作 本文主要给大家展示的是怎么用C#实现对鼠标的操作,有是否在窗体上显示鼠标、把鼠标移动到指定位置、获取鼠标的坐标等。下面将介绍具体操作: 开始是一些参数定义:  //  dwFlags参数定义        const int MOUSEEVENTF_MOVE = 0x0001;     // 移动鼠标         const int MO

☃Clay's♂Blogs 3635

【鸿蒙实战开发】HarmonyOS申请调试签名证书过程

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

HarmonyOS_002的博客 3561

SAP 集成泛微 OA Open API 新建流程申请接口

《SAP ERP 与泛微 OA 的系统集成》系列文章。泛微 Open API 是基于 HTTPS 的 Restful 接口,上篇文章,我已经完成了调用业务接口之前的准备工作,这篇文章我以新建流程申请这个系统集成最重要的接口为例,讲解接口设计、泛微 API 调用的过程、遇到的问题、解决的办法。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 3555

C# SendInput 实现模拟鼠标操作

首先看下 Win API 中SendInput函数描述: UINT WINAPI SendInput(   __in  UINT nInputs,   __in  LPINPUT pInputs,   __in  int cbSize ); 对应的C#代码:[DllImport("user32.dll")]         public static extern UInt3

htsnoopy的专栏 6383

R语言使用caret包的confusionMatrix函数计算混淆矩阵、使用编写的自定义函数可视化混淆矩阵(confusion matrix)

R语言使用caret包的confusionMatrix函数计算混淆矩阵、使用编写的自定义函数可视化混淆矩阵(confusion matrix)

data+scenario+science+insight 3926

c#模拟鼠标键盘操作

一个简单的模拟键盘鼠标操作的类,扩充 VirtualKeys 枚举就可以了,或者直接写!using System;using System.Runtime.InteropServices;using System.Text;class Keyboard   {      const uint KEYEVENTF_EXTENDEDKEY = 0x1;      const uint KEYEVE

FallingStar学习日记 6680

39、FIPA ACL:多代理系统中的标准化通信

本文详细介绍了FIPA ACL(Agent Communication Language)的基本概念、言语行为理论基础以及其在多代理系统(MAS)中的应用。文章涵盖了FIPA ACL的消息格式、信息交流流程、实现与优化方法,并通过智能调度系统的实例展示了其实际应用效果。此外,还探讨了FIPA ACL面临的挑战及未来发展方向,如通信延迟优化、本体简化、安全性增强等。

k8s6orchestrator的博客 381

手把手教你学Simulink--四翼无人机滑模控制器设计与仿真

四翼无人机(Quadcopter)滑模控制(Sliding Mode Control, SMC)是一种鲁棒性很强的非线性控制方法,特别适用于存在模型不确定性和外部扰动的情况。滑模控制器通过强制系统状态进入并保持在一个预定义的滑模面上,从而实现对期望轨迹或姿态的精确跟踪。在这个教程中,我们将使用MATLAB和Simulink来设计并仿真一个基于滑模控制策略的四翼无人机系统。

MHD0815的博客 184

C# 模拟鼠标操作

using System;using System.Collections.Generic;using System.Text;using System.Drawing;using System.Runtime.InteropServices;namespace 通用{    class 模拟鼠标    {        [DllImport("user32.dll")]        sta

szkj2005的专栏 1875

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【C#】模拟键盘鼠标操作

如果你需要更复杂的功能或更好的性能,可以考虑使用专门的库或直接调用 Windows API 函数(如 SendInput)来完成任务。在 C# 中,可以使用 System.Windows.Forms 命名空间中的类来模拟键盘和鼠标的输入事件。兼容性:System.Windows.Forms 命名空间在 .NET Core 和 .NET 5+ 中已被弃用,建议在 .NET Framework 环境中使用。Console.WriteLine("已模拟鼠标左键点击");// 示例:按下 "A" 键。

weixin_42245819的博客 619

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【向重复工作说不】c#之模拟鼠标操作

一.写在前面 作为一个人力资源工作者,会经常遇到填表、报表的事务,其实有时候就是重复再重复的点击鼠标工作,特别是遇到一些复杂的客户端程序、网页程序,诸如用友客户端、社保管理系统等等,就尤其让人头疼。正好这段时间做了很多这方面的工作,搜索了不少的资料,为了转化学习效果,记录于此,温故知新。 二.引用Windows API c#模拟鼠标操作,就必须和WindowsAPI打交道,通过引用它内部的几个函数,从而实现在屏幕的指定位置单击、双击,或者对指定的窗体(能够获得句柄的)、控件进行相关控制操作。相关函数如下:

keenrob的博客 5070

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C#模拟鼠标和键盘操作

本文旨在自己动手实现一个类似于“按键精灵”的桌面软件。第一部分介绍了简单的模拟方式,但是有些软件能够屏蔽掉这种简单模拟带来的效果,因此第二部分将介绍如何从驱动级层面进行模拟。“游戏外挂一般分为三个级别:初级是鼠标、键盘模拟,中级是Call游戏内部函数,读写内存,高级是抓包,封包的“脱机挂”(完全模拟客户端网络数据,不用运行游戏)。用C#写外挂的不是很多,大部分是C++,主要原因是MS的C#目前不支...

FanJin的博客 2万+

关于c#模拟鼠标操作的简单用法

最近要用到c#进行模拟鼠标操作,所以也简单的学习了一下c#进行模拟鼠标操作 自己记录下来,以备后用: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

chunxun1164的博客 248

C#+Win32 API程序控制鼠标的操作 解脱烦重的鼠标繁复操作

命名空间:using System.Runtime.InteropServices; 在程序中添加:         [DllImport("User32")]public extern static void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);     [Dll

gengyiping18的专栏 3064

C# 鼠标操作类

1#region23usingSystem;4usingSystem.Runtime.InteropServices;56#endregion78namespaceWindows.Forms.Base9{10publicclassMouse11{12MouseEventFlagenum#region...

410

C# 系统应用之鼠标模拟技术及自动操作鼠标

游戏程序的操作不外乎两种——键盘输入控制和鼠标输入控制,几乎所有游戏中都使用鼠标来改变角色的位置和方向,本文主要是讲述如何使用C#调用Windows API函数实现鼠标模拟操作的功能.首先通过结合FindWindow和FindWindowEx寻找到窗体的按钮,在通过SetCursorPos或mouse_event函数操作鼠标,同时涉及到通过spy++工具获取窗体消息的信息.同时有代码讲解和gif运行结果,基础文章希望对大家有所帮助~

杨秀璋的专栏 1万+
上一篇: 利用 java.awt.Robot 类来自动完成一些键盘或鼠标的动作,下面是一个小例子
下一篇: 特殊符号大全
贼船叔叔
博客等级 码龄16年 241粉丝 101原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值