I developed C# application which responds to low level mouse clicks. I used mouse hook to do this. The application is working fine, whenever i click any window it responds and perform some task. But i want to do a modification here. I wanted to respond the mouse clicks whenever the click is performed on any buttons on the window. If i click on plain area of window it should not respond. Currently it responds wherever i click. I could not find how to identify whether i clicked on a button or not.
This is my code :
private IntPtr SetHook(MouseHookHandler proc)
{
using (ProcessModule module = Process.GetCurrentProcess().MainModule)
return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(module.ModuleName), 0);
}
private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
if (LeftButtonUp != null)
LeftButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
if (MouseMessages.WM_RBUTTONUP == (MouseMessages)wParam)
if (RightButtonUp != null)
RightButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)));
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
MouseHookHandler lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
Please help me to solve this problem. Thank you.
It seems you are looking for something along the lines of WindowFromPoint.
Call that to see what is under the mouse cursor, then you can query it for whatever properties you are interested in.
Related
I'm trying to detect the horizontal scroll wheel movement globally in .net core 3.1 (or at least movement of any mouse wheel). I want to build this application to work for both, Windows 10 x64 and arm-linux. However, I only need the hook functionality on Windows. I have tried to use the WindowsHook which includes System.Windows.Forms MouseEvents and also the normal MouseKeyHook which it is based on. Both didn't work. The same goes for my implementations of SetWindowsHookEx and the Raw Input API. Trying them in .net core applications only results in a massive input lag as soon as the listeners are in place and no events actually getting triggered. I searched for like two days now and I start to believe you need to be a wizard to get such a global hook to work in .net core. Help would be highly appreciated!
Edit: This is my first time working with hooks and doing low level stuff so I don't understand all of it 100%. I only have this code snippet here atm. For the WindowsHook and MouseKeyHook I just use the examples which you can find on corresponding linked github projects.
Here is the SetWindowsHookEx version, I just call the constructor to get it running and it doesn't even capture hscroll I believe:
using System;
using System.Runtime.InteropServices;
class Intercept_Mouse
{
private static LowLevelMouseProc _proc = HookCallback;
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr _hookID = IntPtr.Zero;
public Intercept_Mouse()
{
_hookID = SetWindowsHookEx(WH_MOUSE_LL, _proc, IntPtr.Zero, 0);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam))
{
Console.WriteLine("Clicked");
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
I made a Form and added a few buttons.
But instead want to press ctrl+NumpadKey1 to do exactly what the buttons would do.
Thus I need to access the program while it's in the background.
Does anyone have any ideas?
I already got the code for when the form is in the front.
Try using global hooks. This article explain how to do this. In short you have to set up hook:
[DllImport(“user32.dll”, CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
On the end you have to unhook:
[DllImport(“user32.dll”, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
And this is how you can create handler:
private static LowLevelKeyboardProc _proc = HookCallback;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
While my C# WinForms app is running, I need to detect when the mouse pointer is moved over a 3rd party application.
I've done some Google'ing but I can't seem to find a useful code example that shows how to set up a Hook Procedure to another application using C# to detect Windows Messages.
Can someone please show me how to setup a C# hook procedure so I can detect the WM_MOUSEMOVE message on another app (e.g. Notepad.exe)?
Below is the C# Low Level Mouse Hook code I was looking for, from the blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx link (that David Heffernan posted)
class InterceptMouse
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
I am using Keyboard Low Level hooks in a desktop application to monitor user activity. Code i am using for hooks is give below.
In this code (upto my knowledge) when I have to start monitoring user activity I call SetHook() this will install hook and I can monitor keys pressed on keyboard. When I want to stop capturing keys i just call UnHook() method.
Problem is when my application starts (SetHook() method is not called yet) my application install hooks automatically and it slows down system. System hangs for for 2-3 seconds every 1 mint.
To diagnose the problem I commented out all the below mentioned code and installed application. Now system works absolutely fine.
I am not sure why is this happening?
Why my application start capturing keys even I did not called SetHook() method yet?
Is there is any other way to capture global keys without using hooks?
Code for Hooks:
public static class WinKeyCapture5 {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
public static DateTime LastKeyPressTime;
public static void SetHook()
{
SetHook(_proc);
}
public static void UnHook()
{
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr _hookID = IntPtr.Zero;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
//if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
//{
int vkCode = Marshal.ReadInt32(lParam);
//if (vkCode == 44)
//ScreenCapture.Load();
LastKeyPressTime = System.DateTime.Now;
//}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
I made a simple hook keyboard in C#, so i have this following code :
private static IntPtr hKeyboardHook = IntPtr.Zero;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x100;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32")]
private static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern short GetKeyState(int vKey);
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
private static LowLevelKeyboardProc _proc = HookCallback;
public void initialization()
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode >= 32 && vkCode < 160)
Console.Write((Keys)vkCode);
if (vkCode == 13)
Console.WriteLine("\n");
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
It works fine with no problem !! my program grip all key pressed in other program and write it on the console.
But i want to have the name of the program where the key is pressed, and i don't know how i can do that.
Anyone can help me ?
You are using a low-level hook (WH_KEYBOARD_LL). Low-level hooks are dispatched before the window manager decides which program will receive the message. Therefore, there is no "name of the program where the key is pressed" because the window manager hasn't yet decided which program the keypress will be delivered to. (You can try to guess by calling GetForegroundWindow.)
(Just curious: What is the ultimate problem you're trying to solve by using a keyboard hook? Maybe there's a better way. I hope you're not writing a keylogger.)