@Timon1221

Как сделать обработчик нажатия клавиш клавиатуры в неактивной форме?

Суть такова: необходимо сделать так, чтобы программа работала в фоне и в нужный момент улавливала сочетание клавиш, например ctrl + лкм.
Читал, что можно реализовать через хуки, но мои познания не особо велики в этом направлении, хочется увидеть наглядный пример.
  • Вопрос задан
  • 2102 просмотра
Решения вопроса 1
NiceHack
@NiceHack
Пока что просто прогер
Хочу уточнить суть вопроса, получается у тебя программа работает в window forms, и ты хочешь чтобы при нажатии определенного сочетания клавиш, она у тебя закрывалась и работала в фоновом режиме, и наоборот также открывалась при сочетании клавиш. Если так, то есть уже готовый класс прямо в window forms, он называется KeyboardHook, просто подключаешь его, вставляешь в код инициализации window forms, где объявляешь его и назначаешь клавиши для него и он будет работать в фоновом режиме и ловить сочетания клавиш, и для него нужно подключать ссылку на библиотеку user32.dll(Он уже встроен в Visual Studio и не надо скачивать стороннюю библиотеку) и только потом его использовать. Надеюсь ты умеешь подключать ссылки на библиотеки. Если нет, то загугли. К слову я работаю в основном на WPF и к нему нельзя подключить эту библиотеку(не знаю почему), только к window forms, и мне приходится вставлять ее вручную как класс(ты тоже можешь не подключать целую библиотеку, а подключить только один класс, скопировать и вставить как свой класс). Вот пример применения этого класса:
using System.Windows.Input; // Не забудь это.
// Ну тут просто привязываешь любые клавиши к действию.
// В первой переменной идет привязка сочетаний клавиш F12 + shift и alt в любом порядке 
// Важная особенность (но я не проверял) первый аргумент это идет любая клавиша которая будет последней
// второй и третий уже сочетание клавиш , т.е. shift + alt + F12 или alt + shift + F12.
var _hotKey1 = new KeyboardHook(Key.F12, KeyModifier.Shift | KeyModifier.Alt, (x) => Show());
var _hotKey2 = new KeyboardHook(Key.F11, KeyModifier.Shift | KeyModifier.Alt, (x) => Hide());

А вот она и сама
// Единственное, я тут поменял все на слово HotKey, для собственного удобства. 
public class HotKey : IDisposable
    {
        private static Dictionary<int, HotKey> _dictHotKeyToCalBackProc;

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        public const int WmHotKey = 0x0312;

        private bool _disposed = false;

        public Key Key { get; private set; }
        public KeyModifier KeyModifiers { get; private set; }
        public Action<HotKey> Action { get; private set; }
        public int Id { get; set; }

        public HotKey(Key k, KeyModifier keyModifiers, Action<HotKey> action, bool register = true)
        {
            Key = k;
            KeyModifiers = keyModifiers;
            Action = action;
            if (register)
            {
                Register();
            }
        }

        public bool Register()
        {
            int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key);
            Id = virtualKeyCode + ((int)KeyModifiers * 0x10000);
            bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode);

            if (_dictHotKeyToCalBackProc == null)
            {
                _dictHotKeyToCalBackProc = new Dictionary<int, HotKey>();
                ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
            }

            _dictHotKeyToCalBackProc.Add(Id, this);

            Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode);
            return result;
        }

        public void Unregister()
        {
            HotKey hotKey;
            if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey))
            {
                UnregisterHotKey(IntPtr.Zero, Id);
            }
        }

        private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled)
        {
            if (!handled)
            {
                if (msg.message == WmHotKey)
                {
                    HotKey hotKey;

                    if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey))
                    {
                        if (hotKey.Action != null)
                        {
                            hotKey.Action.Invoke(hotKey);
                        }
                        handled = true;
                    }
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (disposing)
                {
                    Unregister();
                }

                _disposed = true;
            }
        }
    }

    [Flags]
    public enum KeyModifier
    {
        None = 0x0000,
        Alt = 0x0001,
        Ctrl = 0x0002,
        NoRepeat = 0x4000,
        Shift = 0x0004,
        Win = 0x0008
    }

Надеюсь я правильно понял твой вопрос и смог тебе помочь. И никаких практически знаний не нужно,
рассказал все очень подробно, если что задавай вопросы(Предупреждение, возможны ошибки в коде потому что я это брал со своего старого проекта).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы