Freigeben über


Перехват клавиатуры Windows на C#

 

Один из разработчиков обучающей системы с модулем тестирования обратился ко мне с достаточно простой на первый взгляд задачей – как при запуске экзамена не допустить переключения приложения. При всей простоте, задача немного усложнилась тем, что комплекс был разработан на .NET Framework и подключать вставки native кода на C++ не очень хотелось. На самом деле язык C# на платформе Windows позволяет работать с WIN API. Осталось только привести пример того, как можно осуществить перехват нажатий на клавиши на чуть более низком уровне.

Собственно ниже пример перехвата клавиатуры на языке C#. Пример этот будет работать как на 32х так и на 64 битной Windows. Программа выводит в отладочную консоль нажатия на клавиши в любом приложении, а также производит блокировку нажатия Alt+Tab. Как вы уже понимаете, перехват клавиатуры ведется на уровне всех приложений. При желании можно даже перехватить Ctrl Alt Del но думаю что детали, тем кому это необходимо, выяснят самостоятельно.

 

using System;

using System.Diagnostics;

using System.Runtime.InteropServices;

namespace HookDemoApp

{

    internal class HookDemoHelper

    {

        private const int WH_KEYBOARD_LL = 13;

        private LowLevelKeyboardProcDelegate m_callback;

        private IntPtr m_hHook;

        [DllImport("user32.dll", SetLastError = true)]

        private static extern IntPtr SetWindowsHookEx(

            int idHook,

            LowLevelKeyboardProcDelegate lpfn,

            IntPtr hMod, int dwThreadId);

      [DllImport("user32.dll", SetLastError = true)]

        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("Kernel32.dll", SetLastError = true)]

        private static extern IntPtr GetModuleHandle(IntPtr lpModuleName);

        [DllImport("user32.dll", SetLastError = true)]

        private static extern IntPtr CallNextHookEx(

            IntPtr hhk,

            int nCode, IntPtr wParam, IntPtr lParam);

        private IntPtr LowLevelKeyboardHookProc(

            int nCode, IntPtr wParam, IntPtr lParam)

        {

            if (nCode < 0)

            {

                return CallNextHookEx(m_hHook, nCode, wParam, lParam);

            }

            else

            {

                var khs = (KeyboardHookStruct)

    Marshal.PtrToStructure(lParam,

                          typeof (KeyboardHookStruct));

               

                Debug.Print("Hook: Code: {0}, WParam: {1},{2},{3},{4} ",

                            nCode, wParam, lParam,

     khs.VirtualKeyCode,

                            khs.ScanCode, khs.Flags, khs.Time);

               

                Debug.Print(khs.VirtualKeyCode.ToString());

                if (khs.VirtualKeyCode == 9 &&

                    wParam.ToInt32() == 260 &&

                    khs.ScanCode == 15) //alt+tab

                {

                    System.Console.WriteLine("Alt+Tab pressed!");

                    IntPtr val=new IntPtr(1);

                    return val;                    

                }

                else

                {

                    return CallNextHookEx(m_hHook, nCode, wParam, lParam);

                }

           

            }

        }

        [StructLayout(LayoutKind.Sequential)]

        private struct KeyboardHookStruct

        {

            public readonly int VirtualKeyCode;

            public readonly int ScanCode;

            public readonly int Flags;

            public readonly int Time;

            public readonly IntPtr ExtraInfo;

        }

        private delegate IntPtr LowLevelKeyboardProcDelegate(

            int nCode, IntPtr wParam, IntPtr lParam);

        public void SetHook()

        {

            m_callback =LowLevelKeyboardHookProc;

            m_hHook =SetWindowsHookEx(WH_KEYBOARD_LL,

                m_callback,

                GetModuleHandle(IntPtr.Zero),0);

        }

        public void Unhook()

        {

            UnhookWindowsHookEx(m_hHook);

        }

    }

}

Comments

  • Anonymous
    December 03, 2010
    www.sql.ru/.../actualthread.aspx

  • Anonymous
    January 22, 2011
    Спасибо! Очень кстати, у меня тоже в планах модуль тестирования =)

  • Anonymous
    February 04, 2012
    Пишет что метод main() не найден. ЧТо делать? Как запустить?

  • Anonymous
    May 17, 2012
    Максим, в класс вставьте следующий код: public static void Main() { }

  • Anonymous
    October 10, 2012
    Не могу понять как перехватывать тройное нажатие например Ctrl Alt Del, помогите пожалуйста.

  • Anonymous
    June 23, 2013
    Подскажите а можно как-нибудь реализовать, что-бы перехватывала нажатия в одном определенном приложении?

  • Anonymous
    April 25, 2014
    Портировал в форму - не работает. И консоли до этого тоже не работало.

  • Anonymous
    May 19, 2015
    Не ожидал, работает, и так всё просто.