I've got a simple window form application that turns on capslock when I press space and turns it off if I press a letter.
Problem is that I have to focus on the window for it to work (top-most doesn't work either, top-most doesn't focus it just displaying the window above all other unfocused).
Anyone has any idea how can I make it work even if im writing in a notepad?
Key logging can be used for naughty stuff, and manipulating Caps Lock like that seems rather strange, but since the info is already publicly available, and you know your user stories better than me, I've posted a solution.
Here's an example based on the code snippet posted from keylogger code in C# in the MSDN forum.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class Program
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static bool lastKeyWasLetter = false;
[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);
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run();
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 void ToggleCapsLock()
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
UnhookWindowsHookEx(_hookID);
keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
keybd_event(0x14, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
_hookID = SetHook(_proc);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
if (lastKeyWasLetter)
{
if (Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock))
{
ToggleCapsLock();
}
lastKeyWasLetter = false;
}
Keys key = (Keys)Marshal.ReadInt32(lParam);
if (key == Keys.Space)
{
if (!Control.IsKeyLocked(System.Windows.Forms.Keys.CapsLock))
{
ToggleCapsLock();
}
}
else if (key >= Keys.A && key <= Keys.Z)
{
lastKeyWasLetter = true;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
Paste that into a new Windows application's Program.cs in Visual Studio to try it out.
If you intercept a key down event to turn Caps Lock on and off, then the event is intercepted before the application handles it. This means that turning Caps Lock off when a letter key is pressed will result in the application you are typing in receiving a lower case letter, even directly after a space.
I've assumed you are trying to force the capitalization of the first letter in each word (and if so, you may need to handle other keys such as Return too), so my snippet will only turn Caps Lock off on the next key down event following a letter being pressed. Note that you can't just try and capture the key up, as when typing fast you may hold the initial key down until after you've pressed the following key.
Related
I have a C# windowed application running and I want to close it when I press ESC from anywhere, even when my application does not have focus. How can I implement this?
I found some hook up keyboard which is Low Level Control I have no idea and don't understand.
Use this class:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace myNameSpace
{
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_ALTDOWN = 0x0104;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void Stop()
{
UnhookWindowsHookEx(_hookID);
}
public static event KeyEventHandler OnKeyDown;
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 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 || wParam == (IntPtr)WM_ALTDOWN))
{
var vkCode = (Keys)Marshal.ReadInt32(lParam);
OnKeyDown(null, new KeyEventArgs(vkCode));
}
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);
}
}
In this way:
myNameSpace.InterceptKeys.OnKeyDown+= new KeyEventHandler(myKeyDown);
myNameSpace.InterceptKeys.Start();
that onKeyDown can be like this:
void myKeyDown(object sender, KeyEventArgs e)
{
// Some code for closing you form
// or any thing you need after press Esc
// with e.KeyCode
};
if you want you can set global hook with http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
For those looking for a complete solution to detect global key presses and also make key presses, I've figured it all out and put the code in pastebin.com to "never" be deleted. Note especially InterceptKeys.cs here (do a Ctrl+F):
http://pastebin.com/u7FUhgYr
^ This code is complete, but it's sub-optimal.
Then I improved the code a bit (one change is the new SendKeys function I created which sends whatever key presses/releases you want - much easier to use!). This class here, MakroKeys:
http://pastebin.com/Dedx6hRw
has two static functions that can be used to convert from string to System.Windows.Forms.Keys and vice versa (which would be useful if you want the user to be able to input their own key via text and/or display the currently pressed key via text); and this has the improved MainForm.cs code to go with it (containing the SendKeys function):
http://pastebin.com/BXzmWeMK
(Note the MakroKeys.GetKey("lcontrolkey") call, which demonstrates the usage of that functionality.)
With all of this combined you can do some pretty amazing things. Note also that because this is importing DLL's and calling Windows API functions, you can do this rather easily in e.g. c++ too. You're welcome, world. ;)
I'm experimenting with keyboard events and what you can do with them and I've found alot of tutorials and open source libraries to listen for keyboard events in other processes. I came up with the idea to create a simple 'hack' to lock the computer and then listen for the keyboard events. I figured I could force the user to input their password to unlock their computer and then I would've listened to the user input and thus obtaining the password specified. Here is the simple sample code I found on the internet which will listen for global keyboard events:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
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 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);
}
[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);
}
This works out quiet well, but for some reason there seems to be a exception when listening to keyboard inputs when the computer is locked? I'm not sure why it doesn't work, perhaps it's a security thing. Anyways it would be awesome if one could do this.
If this is on Windows, the locked screen is actually a different Window Station and is not owned by the interactive user, so therefore the interactive user cannot interact with it in any way (as a security measure). To interact with the lock screen, and logon in general, take a look at creating a Credential Provider
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 found a way to capture the Print Screen button in C#. When pressing Alt + Print Screen a simple messagebox pops up saying the keys have been pressed. But it's unresponsive for a couple of seconds right after. I have no idea why this is happening.
Here's the code I use:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
}
/****************************************/
private const int WH_KEYBOARD_LL = 13;
//private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int VK_F1 = 0x70;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
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 delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
Keys number = (Keys)Marshal.ReadInt32(lParam);
if (number == Keys.PrintScreen)
{
if ((wParam == (IntPtr)260 && Keys.Alt == Control.ModifierKeys && number == Keys.PrintScreen))
{
MessageBox.Show("You pressed alt+ print screen");
}
}
}
return CallNextHookEx(IntPtr.Zero, 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);
}
Does anyone have a clue why it's hanging after the messagebox?
Windows cannot dispatch the next keyboard message until the hook callback finished executing. Clearly you do not want to use MessageBox.Show(), that blocks the callback. Windows puts up with that for several seconds before it declares your code broken and disables the hook.
Use Debug.Print() instead.
I need to be able to detect that the shift key is being held, but I don't want to use events or global variables to determine that. Is there an API in C# that lets you ask what keys are currently pressed instead of using the event?
if ((Control.ModifierKeys & Keys.Shift) != 0)
This will also be true if another modifier key is also down (eg, Ctrl+Shift). If you want to check whether Shift alone is pressed without any other modifiers, use
if (Control.ModifierKeys == Keys.Shift)
Note that even this will be true if another non-modifier is down (Eg, Shift+A). If you want to check whether Shift and only Shift is pressed, you'll have to use an API call.
If you're in a class that inherits Control (such as a form), you can remove the Control qualifier. (static properties don't need qualifiers in inherited classes)
Form.ModifierKeys
(static property)
You can install a low-level keyboard hook.
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
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 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);
}
[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);
}
Not sure if this available in C# but you can call GetAsyncKeyState. This method returns the state of a key at the time the method is called.
To call it from C# you'll need to use interop like any other Win32 API.