好吧,所以我無法抗拒這裏的挑戰:)寫了一個小程序,做你想做的。
它是如何工作的:SetWindowsHookEx
讓你放置一個全局鼠標鉤子。 現在,你得到X
,Y
,然後用WindowFromPoint得到你的目標窗口的hWnd
。從這裏你可以做任何你喜歡的事情,就我而言,我發送了一個WM_GETTEXT
來獲得它的頭銜。
這是程序看起來像實現的。一旦你點擊Begin
,它將全局查找右鍵單擊事件,並將它們添加到列表框中。 注意:它需要一個窗口窗體應用程序,該鉤子將無法與控制檯應用程序一起使用。
![enter image description here](https://i.stack.imgur.com/yP91U.png)
使用(只要創建一個默認的WinForms項目,將其更改爲這個):
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
RMouseListener _native;
private void button1_Click(object sender, EventArgs e)
{//start
_native = new RMouseListener();
_native.RButtonClicked +=
new EventHandler<SysMouseEventInfo>(_native_RButtonClicked);
}
private void button2_Click(object sender, EventArgs e)
{//stop
_native.Close();
}
void _native_RButtonClicked(object sender, SysMouseEventInfo e)
{
listBox1.Items.Add(e.WindowTitle);
}
}
執行(這一點的代碼;))
public class SysMouseEventInfo : EventArgs
{
public string WindowTitle { get; set; }
}
public class RMouseListener
{
public RMouseListener()
{
this.CallBack += new HookProc(MouseEvents);
//Module mod = Assembly.GetExecutingAssembly().GetModules()[0];
//IntPtr hMod = Marshal.GetHINSTANCE(mod);
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
IntPtr hModule = GetModuleHandle(module.ModuleName);
_hook = SetWindowsHookEx(WH_MOUSE_LL, this.CallBack, hModule, 0);
//if (_hook != IntPtr.Zero)
//{
// Console.WriteLine("Started");
//}
}
}
int WH_MOUSE_LL = 14;
int HC_ACTION = 0;
HookProc CallBack = null;
IntPtr _hook = IntPtr.Zero;
public event EventHandler<SysMouseEventInfo> RButtonClicked;
int MouseEvents(int code, IntPtr wParam, IntPtr lParam)
{
//Console.WriteLine("Called");
if (code < 0)
return CallNextHookEx(_hook, code, wParam, lParam);
if (code == this.HC_ACTION)
{
// Left button pressed somewhere
if (wParam.ToInt32() == (uint)WM.WM_RBUTTONDOWN)
{
MSLLHOOKSTRUCT ms = new MSLLHOOKSTRUCT();
ms = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
IntPtr win = WindowFromPoint(ms.pt);
string title = GetWindowTextRaw(win);
if (RButtonClicked != null)
{
RButtonClicked(this, new SysMouseEventInfo { WindowTitle = title });
}
}
}
return CallNextHookEx(_hook, code, wParam, lParam);
}
public void Close()
{
if (_hook != IntPtr.Zero)
{
UnhookWindowsHookEx(_hook);
}
}
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);
public static string GetWindowTextRaw(IntPtr hwnd)
{
// Allocate correct string length first
//int length = (int)SendMessage(hwnd, (int)WM.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
StringBuilder sb = new StringBuilder(65535);//THIS COULD BE BAD. Maybe you shoudl get the length
SendMessage(hwnd, (int)WM.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public UIntPtr dwExtraInfo;
}
enum WM : uint
{//all windows messages here
WM_RBUTTONDOWN = 0x0204,
WM_GETTEXT = 0x000D,
WM_GETTEXTLENGTH = 0x000E
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
'SetWindowsHookEx'允許你全局捕獲鼠標事件。看到[這篇文章]上的最後一個答案(http://stackoverflow.com/questions/11607133/global-mouse-event-handler)。它有一個完整的代碼示例。 – gideon
@gideon:謝謝,但我相信這隻會給我低級別的鼠標事件(如座標)。我認爲通過攔截Windows消息我可以確定被點擊的實際控制。 – Lou
您可以查看可訪問性API。他們可能能夠做你需要的。 – CodesInChaos