When I set up non-global WH_KEYBOARD hook, it works fine and all keys are catched. But if I press Alt+Tab and then return to the window, hook stops its working with no reason.
This is my hook proc where I'm trying to block all keyboard messages for proccess with id = root:
private static IntPtr HookCallback (int nCode, IntPtr wParam, IntPtr lParam)
{
var proc = 0u;
GetWindowThreadProcessId(GetForegroundWindow(), out proc);
if (proc != root) return CallNextHookEx(hooks[0], nCode, wParam, lParam);
return new IntPtr(1);
}
For developing I use 32bit Windows in VirtualBox.
UPDATE:
It also doesn't depend on blocking or passing parameters to the next hook: code variant that do nothing then calling next hook stops working after Alt+Tab too. Losing focus and activating of the window doesn't stop hook if it was done not with Alt+Tab.
After looking for some samples and analysing my code I've found how to solve this "bug". I should set last two parameters in SetWindowsHookEx function in such way:
SetWindowsHookEx(HookType.WH_KEYBOARD, HookCallback,
IntPtr.Zero, GetCurrentThreadId());
but not like this:
SetWindowsHookEx(HookType.WH_KEYBOARD, HookCallback,
GetModuleHandle(curModule.ModuleName), 0);
Related
I have a virtual mouse driver and an actual mouse on my computer.
I'm using LowLevelMouseProc to capture events windows wide and I would like to not process events from the virtual mouse.
I cannot use RawInput as I need to process message of another process.
Is there any way to know which device has sent the message ?
Forcing the dwExtraInfo also on a real mouse device may help me if possible.
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
MSLLHOOKSTRUCT hookStruct;
if (nCode < 0)
{
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
hookStruct = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
// I'd like to know from here which mouse has sent the message.
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
There is nothing exposed from the .NET Windows API to distinguish between different mice. There was a Microsoft SDK for multiple inputs at one time but it was dropped before Windows 10 so it likely doesn't work anymore.
rawinput-sharp shows how to do it but it uses raw input, as the name suggests, which I know you said you don't want to do. This limitation you have put on yourself has gotten you stuck. It's like saying "how do I see the screen with my eyes closed?"
Perhaps you could correlate the two events somehow to get the filter you are looking for. Or maybe you could filter out all events from the LowLevelMouseProc and pass the raw input from just one device into the LowLevelMouseProc.
There is a related discussion from the GameDev SE site.
I am trying to make a little program that installs a global hook and catches keyboard input.
For now, I am trying to make every input changed to 'X' for example.
So if i write anywhere "hello" it will actually write "XXXXX".
I succeeded with hooking and even stopping any input from passing my hook but I can't figure out how to change the input.
The relevant method:
IntPtr HookCallBack(int nCode, IntPtr wParam, IntPtr lParam)
{
// Trying to change the input.
Marshal.WriteInt32(lParam, 88);
// Locked down
if (isKeyboardLockedDown)
return new IntPtr(1); // A non-zero return value blocks additional processing of key strokes.
// Not locked down.
else
return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
}
As written above - if I understand right - lParam is the address where the input key is stored.
Therefor I overwrite it with "X".
That method doesn't work for some reason.
Any suggestions?
If the input is X:
Invoke CallNextHookEx()
Otherwise
Do not invoke CallNextHookEx(). Instead, call SendInput to post an X.
SendInput
Synthesizes keystrokes, mouse motions, and button clicks.
Note: In general it is unwise not to invoke CallNextHookEx(). Then again, it is in general not wise to replace all input with X :-)
iv'e done a similar project in C. Instead of changing the data i generated input. It works smoothly and not slowing the typing process down.
I used a global flag. True for input i generate and false for input from the user.
This is pretty much how it looked:
HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(flag){
flag = FALSE;
return CallNextHookEx(NULL, nCode, wParam, lParam);}
else{
flag = TRUE;
keybd_event(what ever you want);
return 0;}
}
I get this problem only with thread-specific hooks. WH_KEYBOARD_LL and WH_MOUSE_LL work both fine as the dll doesn't have to be injected somewhere. This is one of the callback procedures form the dll:
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HookData[WH_KEYBOARD + 1].lpfn(nCode, wParam, lParam);
return CallNextHookEx(HookData[WH_KEYBOARD + 1].hhook, nCode, wParam, lParam);
}
lpfn is the method from the managed code (C# project) that will marshal and store the parameters for further analisys. When that method is called, the process of the thread I want to monitor crashes for "access violation" (the thread I use to test the hook is that of the window of notepad).
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, L"Value", L"KeyboardHook", MB_OK);
return CallNextHookEx(HookData[WH_KEYBOARD + 1].hhook, nCode, wParam, lParam);
}
I tried then this way and it worked fine, showing a message box everytime I pressed a key when the window of notepad was focused.
So, is there a way to call that method? Or maybe am I calling that method in a wrong way? If I can't call that method, is there another way to pass the callback parameters to the C# project everytime the callback procedure is called?
I am using a class i got from this blog:
http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
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);
}
This function get the key code for a single key, i wanted to alter it so i can catch ctrl+C so i altered the above function as follows:
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if ((Keys)(vkCode) == Keys.C && (Control.ModifierKeys == Keys.Control))
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
The problem is Control.ModifierKeys always returns NONE, i googled too much with any results, i want to note that i am using this code in class in a separate module in the solution. What am i doing here, please provide a solution.
Yes, this will go wrong in general but especially when your program does itself not have a GUI or uses a hidden window. Windows maintains keyboard state for each individual process, it is updated when a program receives a keyboard message. This is necessary because key strokes are stored in the message queue and get retrieved by the program later, sometimes much later. The problem with a keyboard hook is that it was another process that got the message, not yours. You've still got the stale keyboard state.
To make it truly reliable, you'll need to know the keyboard state of the other process. But that's not something you can get to, the GetKeyboardState() function only allows permitting retrieving your own state. This in general makes translating key strokes to typing keys very difficult. A WH_KEYBOARD hook is a much better solution but you cannot write such a hook in C#.
A workaround is to track the state of the Control key yourself. Or by pinvoking GetAsyncKeyState() to check the actual unbuffered state of the Control key.
That won't work for you!
The implementation of Control.ModifierKeys just calls the Windows API function GetKeyState() three times, with parameters 0x10, 0x11 and 0x12 in turn, and ors the results appropriately.
But the state is tied to which message from the message queue is being processed.
I think you need to use PInvoke to call the Windows API function GetAsyncKeyState() instead.
I'm running my own kiosk application as the shell (replacing HKLM/Software/Microsoft/Windows NT/winlogon/shell).
The application needs to be able to turn off the monitor and I was using Process.Start("scrnsave.scr") to do this. It works on my dev machine but not when the shell is replaced.
It's clearly because the UseShellExecute is set to true, but when I set it to false I can't get the screensaver to run. Using explorer.exe as the command and scrnsave.scr as the argument just causes an explorer window to open.
Is there a switch I can pass to explorer to get it to run the screensaver or is there another way to achieve the same thing?
Thanks.
You can start the screen saver by sending a windows message to the system.
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, 0)
You will need the following definitions
static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
static readonly IntPtr SC_SCREENSAVE = new IntPtr(0xf140);
const uint WM_SYSCOMMAND = 0x112;
[DllImport("User32",SetLastError=true)]
extern static int SendMessage(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
IntPtr lParam);
Which you can then use as follows
SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, IntPtr.Zero);