Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
196 views
in Technique[技术] by (71.8m points)

c# - Background Key Press Listener

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...