背景按键监听器

发布于 2024-11-04 15:00:19 字数 148 浏览 5 评论 0 原文

我有一个简单的窗口窗体应用程序,当我按空格时打开大写锁定,如果按字母则将其关闭。

问题是我必须专注于窗口才能工作(最顶层也不起作用,最顶层也不聚焦它,只是将窗口显示在所有其他未聚焦的窗口之上)。

任何人都知道即使我在记事本中书写,我怎样才能使其工作?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

回忆躺在深渊里 2024-11-11 15:00:19

按键记录可用于顽皮的事情,并且像这样操纵大写锁定似乎相当奇怪,但由于该信息已经公开可用,并且您比我更了解您的用户故事,所以我发布了一个解决方案。

以下是基于 C# 键盘记录器代码

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);
    }
}

将其粘贴到 Visual Studio 中新 Windows 应用程序的 Program.cs 中进行尝试。

如果您拦截按键事件以打开和关闭大写锁定,则该事件将在应用程序处理之前被拦截。这意味着按下字母键时关闭大写锁定将导致您正在键入的应用程序收到小写字母,即使紧接在空格之后也是如此。

我假设您正在尝试强制每个单词中第一个字母的大写(如果是这样,您可能还需要处理其他键,例如 Return ),所以我的代码片段只会在按下下一个键时关闭大写锁定按下字母后发生的事件。请注意,您不能只是尝试捕获该键,因为在快速打字时,您可能会按住第一个键,直到按下下一个键。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文