I'm working on a program, who need to detect when the user press the keyboard or use his mouse, even if the program is minimized or not focused.
I think I have to use the windows API, keybd_event (user32), but I don't know how to use the "listener" of this event. I have something like that:
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,UIntPtr dwExtraInfo);
void PressKey(byte keyCode)
{
//My code here
}
I did some research, but it's the first time I have to use DllImport, so I don't know how to continue ...
Thanks
(Ps:Sorry about my bad English, this is not my native language :) )
(PPs: I've read all of your answers, but it takes a while to read every link, so I'll work on it tonight, but I think I will find the answer. Anyway, thanks for the links everybody ;) )
Edit: So I just finished my code and it's work :) It looks something like:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
Thanks for the help guys ;)
You will need to hook into Windows OS with SetWindowsHookEx function. You should read the article Keyloggers: How they work and how to detect them posted by SecureList to get a understanding ofthe process.
I have always got a good performance by using RegisterHotKey/UnregisterHotKey functions. Sample code:
[DllImport("User32")]
public static extern bool RegisterHotKey(
IntPtr hWnd,
int id,
int fsModifiers,
int vk
);
[DllImport("User32")]
public static extern bool UnregisterHotKey(
IntPtr hWnd,
int id
);
public const int MOD_SHIFT = 0x4;
public const int MOD_CONTROL = 0x2;
public const int MOD_ALT = 0x1;
public const int WM_HOTKEY = 0x312;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0)
{
IntPtr lParamCTRLA = (IntPtr)4259842;
IntPtr lParamB = (IntPtr)4325376;
if (m.LParam == lParamCTRLA)
{
MessageBox.Show("CTRL+A was pressed");
}
else if (m.LParam == lParamB)
{
MessageBox.Show("B was pressed");
}
}
base.WndProc(ref m);
}
private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
RegisterHotKey(this.Handle, 0, MOD_CONTROL, (int)Keys.A);
RegisterHotKey(this.Handle, 0, 0, (int)Keys.B);
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0);
}
You can "register" as many keys (or combination of keys) as you want by emulating the shown structure. All the registered keys will get inside the condition if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0); if they are pressed at all (independently upon the program currently being selected). The easiest way to know the specific key/combination being pressed is relying on m.LParam (I got the two values I am including after a quick test with the given keys). You can do a quick research to find out a list of LParam or further constant modifiers (wheel of the mouse, for example).
The final code:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
Related
We have a advanced software written by using c# ( windows forms ). In their we have 1000 or more textboxes. I need to validate user input on all these textboxes to stop entering special characters and any scripts. Textboxes are hard coded.
for eg :
I can use following piece of code on every keypress to check whether user has entered the allowed characters or not.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
var regex = new Regex(#"[^a-zA-Z0-9\s]");
if (regex.IsMatch(e.KeyChar.ToString()))
{
e.Handled = true;
}
}
but then we have to implement this on every textboxes key press events ( if there is no other solution this is the last thing to do). Is there any way to handle this from a single place and affect for every textboxes (on some places textboxes have their own key press events as well). What I need is a common method which will be fire on every key press events of any textbox.
Solution : Create a Custom Control derived from TextBox (or TextBoxBase) that contains all the logic required for my validation, so it's all done in one place.
But still I have to again change all the existing textboxes my new textbox.
Is there any way to change behavior of current event handler?
Note: What I need is to override current keypress event of the textbox and run my validation code plus need to run if there is any explicitly mentioned code inside key press events.
If you want to add the KeyDown Event to all TextBoxes you can loop through them and add the same EventHandler for all of them.
To do that first of all we need to create a function that loop through all our TextBoxes.
GetChildControls Function:
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control)
where TControl : Control
{
var children = (control.Controls != null) ?
control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>();
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children);
}
We can now use that function after the InitializeComponent(); to assign the Txt_KeyDown() EventHandler to all TextBoxes.
Calling the Function:
public Example() {
InitializeComponent();
var allTextBoxes = this.GetChildControls<TextBox>();
foreach (TextBox tb in allTextBoxes)
{
tb.KeyDown += Txt_KeyDown;
}
}
private void Txt_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) {
// Your code here
}
"Is there any way to handle this from a single place and affect for
every textboxes"
There's a few ways. But it seems you don't want to edit the textbox itself, so there's only one reliable way I'm aware of; attaching a global keyboard hook. Code follows:
class GlobalKeyboardHook
{
#region DLL Imports
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int hookEventId, keyboardProc callback, IntPtr handleInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr handleInstance);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr ignoredParameter, int hookCode, int wParam, ref KeyboardHookStruct lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string libFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion DLL Imports
#region Class Declarations
private delegate int keyboardProc(int code, int wParam, ref KeyboardHookStruct lParam);
private keyboardProc kbdProc;
public struct KeyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int extraInfo;
}
private static class KeyboardMessages
{
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_SYSKEYDOWN = 0x104;
public const int WM_SYSKEYUP = 0x105;
}
IntPtr HookPointer = IntPtr.Zero;
IntPtr ModuleInstance = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion Class Declarations
#region Class Functions
public GlobalKeyboardHook() {
EnableHook(true, null);
}
public GlobalKeyboardHook(Process P) {
EnableHook(true, P);
}
~GlobalKeyboardHook() {
EnableHook(false, null);
}
public void EnableHook(bool Enabled)
{
EnableHook(Enabled, null);
}
public void EnableHook(bool Enabled, Process P) {
if (Enabled)
{
HookPointer = SetWindowsHookEx(KeyboardMessages.WH_KEYBOARD_LL, kbdProc = HookCallback, ModuleInstance = P == null ? LoadLibrary("User32") : GetModuleHandle(P.MainModule.ModuleName), 0);
}
else
{
UnhookWindowsHookEx(HookPointer);
HookPointer = IntPtr.Zero;
ModuleInstance = IntPtr.Zero;
kbdProc = null;
}
}
public int HookCallback(int code, int wParam, ref KeyboardHookStruct lParam) {
if (code >= 0) {
KeyEventArgs key = new KeyEventArgs((Keys)lParam.vkCode);
if ((wParam == KeyboardMessages.WM_KEYDOWN || wParam == KeyboardMessages.WM_SYSKEYDOWN) && (KeyDown != null)) {
KeyDown(this, key) ;
} else if ((wParam == KeyboardMessages.WM_KEYUP || wParam == KeyboardMessages.WM_SYSKEYUP) && (KeyUp != null)) {
KeyUp(this, key);
}
if (key.Handled)
return 1;
}
return CallNextHookEx(HookPointer, code, wParam, ref lParam);
}
#endregion Class Functions
}
To activate we add the following:
GlobalKeyboardHook ghk = new GlobalKeyboardHook(Process.GetCurrentProcess());
Type tbType = typeof(TextBox);
ghk.KeyDown += new KeyEventHandler(() => {
if (typeof(this.ActiveControl) == tbType)
RunValidation(this.ActiveControl.Text);
});
Once you have the boilerplate hook, adding validation becomes pretty simple. No loops means you're not wasting processor time iterating over a thousand text boxes.
Just remember this will apply to ALL controls of type TextBox within the current process. If you add a custom TextBox control or don't want to check all of them - that should be accounted for prior to calling RunValidation().
This is the first code I've written in c#, and my first question to Stackoverflow...apologies up front if I'm doing everything wrong! :-/
I've tried to implement the Public Class RTFScrolledToBottom written by LarsTech that was posted as answered the question here:
Get current scroll position from rich text box control?
In the public Form1() code block, this line is generating a CS1061 error:
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
object does not contain a definition for ScrolledToBottom and no accessible extension method ScrolledToBottom accepting a first argument of type object could be found (are you missing a using directive or an assembly reference?)
Thanks in advance for any assistance pointing me to what I'm screwing up!!
Cheers!
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private object rtfScrolledBottom1;
public Form1()
{
InitializeComponent();
int rtfScrolledBottom1_ScrolledToBottom = 0;
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
}
public class RTFScrolledBottom : RichTextBox
{
public event EventHandler ScrolledToBottom;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_USER = 0x400;
private const int SB_VERT = 1;
private const int EM_SETSCROLLPOS = WM_USER + 222;
private const int EM_GETSCROLLPOS = WM_USER + 221;
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
public bool IsAtMaxScroll()
{
int minScroll;
int maxScroll;
GetScrollRange(this.Handle, SB_VERT, out minScroll, out maxScroll);
Point rtfPoint = Point.Empty;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref rtfPoint);
return (rtfPoint.Y + this.ClientSize.Height >= maxScroll);
}
protected virtual void OnScrolledToBottom(EventArgs e)
{
if (ScrolledToBottom != null)
ScrolledToBottom(this, e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
base.OnKeyUp(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
}
base.WndProc(ref m);
}
}
}
You have defined rtfScrolledBottom1 as object and object doesn't have any event. You need to define it as RTFScrolledBottom. You also can drop an instance of the RTFScrolledBottom control from toolbox and use it like any other control.
Alternative solution
As an alternative to the solution which you found in the linked post, here is another solution which Works with RichTextBox without creating a derived control, while you can put the logic in a derived control and make it more reusable, like what has done in the linked post.
You can handle VScroll event of the RichTextBox and get the scroll position by calling GetScrollInfo method. Then in the SCROLLINFO if nPage + nPos == nMax, it means the scroll is at bottom:
[StructLayout(LayoutKind.Sequential)]
struct SCROLLINFO {
public int cbSize;
public ScrollInfoMask fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollInfoMask : uint {
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
[DllImport("user32.dll")]
private static extern bool GetScrollInfo(IntPtr hwnd, SBOrientation fnBar,
ref SCROLLINFO lpsi);
public enum SBOrientation : int { SB_HORZ = 0x0, SB_VERT = 0x1 }
private void richTextBox1_VScroll(object sender, EventArgs e)
{
var info = new SCROLLINFO() {
cbSize = (Marshal.SizeOf<SCROLLINFO>()),
fMask = ScrollInfoMask.SIF_ALL
};
GetScrollInfo(richTextBox1.Handle, SBOrientation.SB_VERT, ref info);
if (info.nPage + info.nPos == info.nMax)
{
//VScroll is at bottom
}
}
I would like to use the numlock button for something other than numlock. So basically I would like to turn off numlock when it is pressed and keep it off. I can capture the button press but it still toggles on/off. I want it off, always. Any suggestions?
Not sure WHY anyone would like to know WHY I want this to be done but here is the reason: I have a bluetooth numeric keypad that I want to use to control a machine. Does that justify the question?
After a couple hours of research I came across the following code which did the trick:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class SetNumlockKeyOn
{
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal int type;
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
int dummy1;
int dummy2;
internal int type1;
internal short wVk1;
internal short wScan1;
internal int dwFlags1;
internal int time1;
internal IntPtr dwExtraInfo1;
int dummy3;
int dummy4;
}
[DllImport("user32.dll")]
static extern int SendInput(uint nInputs, IntPtr pInputs, int cbSize);
public static void SetNumlockOn()
{
if (Control.IsKeyLocked(Keys.NumLock)) return;
const int mouseInpSize = 28;//Hardcoded size of the MOUSEINPUT tag !!!
INPUT input = new INPUT();
input.type = 0x01; //INPUT_KEYBOARD
input.wVk = 0x90; //VK_NUMLOCK
input.wScan = 0;
input.dwFlags = 0; //key-down
input.time = 0;
input.dwExtraInfo = IntPtr.Zero;
input.type1 = 0x01;
input.wVk1 = 0x90;
input.wScan1 = 0;
input.dwFlags1 = 2; //key-up
input.time1 = 0;
input.dwExtraInfo1 = IntPtr.Zero;
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize * 2);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize); //Hardcoded size of the MOUSEINPUT tag !!!
//if (result == 0 || Marshal.GetLastWin32Error() != 0)
// Console.WriteLine(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(pI);
}
}
Here's an example:
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}
How do I achieve this in a WinForms container control when the scroll bars are visible?
Highlighted here (Google Chrome browser):
EDIT: This cursor is the only one that is visible on a screenshot. I hope it's clear what i mean.
EDIT:
Tried this on my control. Does not work.
const int WM_MBUTTONDOWN = 0x207;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MBUTTONDOWN)
DefWndProc(ref m);
else
base.WndProc(ref m);
}
Here's what I have so far. It exits "reader mode" if I release the middle button, and I haven't implemented scrolling within the control (I used a textbox), but it may give you something to start with.
[DllImport("comctl32.dll", SetLastError=true, EntryPoint="#383")]
static extern void DoReaderMode(ref READERMODEINFO prmi);
public delegate bool TranslateDispatchCallbackDelegate(ref MSG lpmsg);
public delegate bool ReaderScrollCallbackDelegate(ref READERMODEINFO prmi, int dx, int dy);
[StructLayout(LayoutKind.Sequential)]
public struct READERMODEINFO
{
public int cbSize;
public IntPtr hwnd;
public int fFlags;
public IntPtr prc;
public ReaderScrollCallbackDelegate pfnScroll;
public TranslateDispatchCallbackDelegate fFlags2;
public IntPtr lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public UInt32 message;
public IntPtr wParam;
public IntPtr lParam;
public UInt32 time;
public POINT pt;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
private bool TranslateDispatchCallback(ref MSG lpMsg)
{
return false;
}
private bool ReaderScrollCallback(ref READERMODEINFO prmi, int dx, int dy)
{
// TODO: Scroll around within your control here
return false;
}
private void EnterReaderMode()
{
READERMODEINFO readerInfo = new READERMODEINFO
{
hwnd = this.textBox1.Handle,
fFlags = 0x00,
prc = IntPtr.Zero,
lParam = IntPtr.Zero,
fFlags2 = new TranslateDispatchCallbackDelegate(this.TranslateDispatchCallback),
pfnScroll = new ReaderScrollCallbackDelegate(this.ReaderScrollCallback)
};
readerInfo.cbSize = Marshal.SizeOf(readerInfo);
DoReaderMode(ref readerInfo);
}
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Middle)
{
EnterReaderMode();
}
}
The RichTextBox control does it by default when you press the mouse wheel button.
Edit: Sorry I misunderstood and thought you were asking about doing it within a textbox not a container control
I made an application that needs to handle specific keyboard presses even when the window is not active, now I have this and it works great; however the handled keys are still being propagated to windows (not sure if my app is handling them first, so I may be backwards about that).
Is there any way to have it so my app can handle the key presses I want but not have the keys be sent to the current application/windows.
EX) I have my app open in the background monitoring the number pad for presses, every time I press a number key on the number pad I want to add that number to a text box for display purposes. Now I have chrome open and have the cursor in the address bar, I want to be able to press the number keys while having my app handle them but not having them show up in chromes address bar.
Thanks.
This is basically a very simplistic key logger.
EDIT)
Keyboard Hook
#endregion
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class GlobalKeyboardHook
{
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
hook();
}
~GlobalKeyboardHook()
{ unhook(); }
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
KeyDown(this, kArg);
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
KeyUp(this, kArg);
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
}
Usage of GlobalKeyboardHook
GlobalKeyboardHook gHook;
private void Form1_Load(object sender, EventArgs e)
{
gHook = new GlobalKeyboardHook(); // Create a new GlobalKeyboardHook
// Declare a KeyDown Event
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
// Add the keys you want to hook to the HookedKeys list
foreach (Keys key in Enum.GetValues(typeof(Keys)))
gHook.HookedKeys.Add(key);
}
// Handle the KeyDown Event
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
textBox1.Text += ((char)e.KeyValue).ToString();
}
private void button1_Click(object sender, EventArgs e)
{
gHook.hook();
}
private void button2_Click(object sender, EventArgs e)
{
gHook.unhook();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
gHook.unhook();
}
In your hookProc, you must not call return CallNextHookEx(Hook, Code, wParam, ref lParam); if you dont want the WM_KEYS to propagate.
If you do call CallNextHookEx, the messages will be propagated.
Btw, you are aware that you are using a Global hook, and not a thread specific hook ? So you are capturing ALL key presses, and not only the ones relative to your app.