Слушатель нажатия клавиш фона - PullRequest
4 голосов
/ 02 мая 2011

У меня есть простое приложение в форме окна, которое включает capslock, когда я нажимаю пробел, и выключает его, если я нажимаю букву.

Проблема в том, что мне нужно сосредоточиться на окне, чтобы оно работало (верхний-самый тоже не работает, верхний-самый не фокусирует его, просто отображая окно над всеми другими не сфокусированными).

У кого-нибудь есть идеи, как заставить его работать, даже если я пишу в блокноте?

1 Ответ

16 голосов
/ 02 мая 2011

Журналирование клавиш можно использовать для непослушных вещей, и манипулирование Caps Lock вроде этого кажется довольно странным, но, поскольку информация уже общедоступна, и вы знаете свои пользовательские истории лучше меня, я опубликовал решение.

Вот пример, основанный на фрагменте кода, отправленном из кода кейлоггера в C # на форуме MSDN.

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

Вставьте его в файл Program.cs нового приложения Windows в VisualStudio, чтобы попробовать.

Если вы перехватываете событие нажатия клавиши, чтобы включить и выключить Caps Lock, то это событие перехватывается до того, как приложение его обработает.Это означает, что отключение Caps Lock при нажатии буквенной клавиши приведет к тому, что приложение, которое вы набираете, получит строчную букву, даже сразу после пробела.

Я предположил, что вы пытаетесь принудительно вызватьзаглавная буква первой буквы в каждом слове (и если это так, возможно, вам придется обрабатывать и другие клавиши, такие как Return), поэтому мой фрагмент отключит функцию Caps Lock только при следующем событии нажатия клавиши после нажатия буквы.Обратите внимание, что вы не можете просто попытаться нажать клавишу вверх, так как при быстром наборе вы можете удерживать начальную клавишу до тех пор, пока не нажмете следующую клавишу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...