2013-03-15 3 views
4

У меня есть приложение, которое всегда проверяет, нажата ли клавиша типа F12. Это не нужно в центре внимания моего главного окна моего приложения. Я попробовал этот код:Захват ключа без фокусировки окна

public int a = 1; 
    // DLL libraries used to manage hotkeys 
    [DllImport("user32.dll")] 
    public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); 
    [DllImport("user32.dll")] 
    public static extern bool UnregisterHotKey(IntPtr hWnd, int id); 

    const int MYACTION_HOTKEY_ID = 1; 

    public Form1() 
    { 
     InitializeComponent(); 
     // Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8 
     // Compute the addition of each combination of the keys you want to be pressed 
     // ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6... 
     RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); 
    } 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID) 
     { 

      a++; 
      MessageBox.Show(a.ToString()); 
     } 
     base.WndProc(ref m); 
    } 

я ставлю 0 этой линии RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); так, что только тогда, когда F12 нажимается она захватит.

Но это не сработало. Как я могу это решить?

Здесь я не мог понять некоторые строки:

const int MYACTION_HOTKEY_ID = 1; 
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID 
base.WndProc(ref m); 

Может кто-нибудь помочь мне понять эти строки?

ответ

1

Ваш код не имеет вреда. Но здесь это не работает, потому что зарезервирован ключ F12. Вы можете попробовать с помощью другой клавиши, такой как F10, F11 и т. Д.

+0

Примечание: оно также может не работать, если вы меняете свойство ShowInTaskbar, поскольку окно уничтожено и зарегистрированный HotKey с ним. Просто узнал трудный путь. – adiuva

1

Чтобы сделать аналогичную вещь, я применил низкоуровневый клавиатурный крючок, используя SetWindowsHookEx. Это замалчивает все сообщения клавиатуры, проходящие через Windows, и позволяет вам их проверять и при необходимости предотвращать их дальнейшее продвижение.

Посмотрите на my KeyboardHandling project в моем RocketLauncher GitHub hobby project. Вы можете взять то, что вам нужно непосредственно от этого. Я тоже скоро сделаю пакет nuget.

+0

Но если я сменю RegisterHotKey (this.Handle, MYACTION_HOTKEY_ID, 2, (int) Keys.F12), а Ctrl + F10 работает, даже если это не фокус. – 2013-03-15 09:32:51

+0

Достаточно справедливо - я сделал предположение, что это было то же самое, что устанавливать их в дизайнере. –

+1

Я бы *** решительно *** пользу, используя глобальную горячую клавишу, зарегистрированную через 'RegisterHotKey', в отличие от глобальной клавиатуры. Крюки с глобальным охватом * чрезвычайно * тяжелы и дороги и поэтому должны использоваться только там, где они абсолютно необходимы. Здесь дело не в этом (хотя я не уверен в вашем приложении для запуска, но он может и не быть). –

0

Я не знаю, почему, но я чувствую, что это связано с this вопрос ... так что я буду пытаться объяснить это еще раз:

const int MYACTION_HOTKEY_ID = 1; 

где вы сохранить целое число, используется для идентификации горячей клавиши. Если вам необходимо зарегистрировать более чем на горячую клавишу, вы должны объявить другие целые поля, идентифицирующие другие горячие клавиши:

const int ANOTHER_ACTION_HOTKEY_ID = 2; 
const int AND_ANOTHER_ACTION_HOTKEY_ID = 3; 

Затем

m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID 

является условием, которое позволяет узнать, какие горячие клавиши есть был введен пользователем.

0x0312 (также объявлен WM_HOTKEY в документации, которые можно найти here к примеру), чтобы знать, если зарегистрированная клавиша была нажата:

Когда клавиша нажата, то система ищет совпадение со всеми горячими клавишами. Найдя совпадение, система отправляет сообщение WM_HOTKEY в очередь сообщений окна, с которым связана горячая клавиша. Если горячая клавиша не связана с окном, сообщение WM_HOTKEY отправляется в поток, связанный с горячей клавишей.


Согласно documentation, вы не можете использовать F12 горячие клавиши:

Ключ F12 резервируется для использования отладчика во все времена, поэтому он не должен быть зарегистрирован как горячую клавишу. Даже если вы не отлаживаете приложение, F12 зарезервирован в случае, если отладчик режима ядра или отладчик точно вовремя резидентный.

+0

0x0312 для чего ?? – 2013-03-15 09:36:29

+0

@tuilip: Смотрите мое редактирование. – Otiel

2

Но это не сработало. Как я могу это решить?

Что значит «это не сработало»? Код в вашем вопросе выглядит правильно для меня.

Единственная причина, по которой он может не работать, заключается в том, что функция RegisterHotKey возвращает ошибку, и вы не проверяете ее. Чтобы сделать эту работу, вам нужно добавить SetLastError attribute к ее объявлению, из-за чего среда выполнения кэширует код ошибки Win32, который он устанавливает. Как только это будет сделано, вы можете проверить этот код ошибки (если функция возвращает false), вызвав GetLastWin32Error function. Я рекомендую использовать результат этой функции для генерации и выброса Win32Exception.

Измените декларацию RegisterHotKey следующим образом:

[DllImport("user32.dll", PreserveSig = false)] 
public static extern bool RegisterHotKey(IntPtr hWnd, 
             int id, 
             uint fsModifiers, 
             Keys key); 

И ваш вызов функции следующим образом:

if (!RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, Keys.F12)) 
{ 
    throw new Win32Exception(Marshal.GetLastWin32Error()); 
} 

После того, как это сделано, я подозреваю, что вы будете видеть исключение получать накинула сообщение об ошибке:

Горячая клавиша уже зарегистрирована

Ну, это значительно упрощает отладку проблемы, не так ли? Скорее всего, вам нужно выбрать другую горячую клавишу, так как функция документация RegisterHotKey говорит нам явно, что:

Ключ F12 зарезервирован для использования отладчика во все времена, так что это не должно быть зарегистрированный как горячая клавиша. Даже если вы не отлаживаете приложение, F12 зарезервирован на случай, если резидентный режим отладки ядра или отладчик точно в срок.

Когда я запускаю код и зарегистрировать F11 как горячие клавиши, она работает очень хорошо для меня.


Здесь я не мог понять некоторые строки:

const int MYACTION_HOTKEY_ID = 1; 
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID 
base.WndProc(ref m); 

Может кто-нибудь помочь мне понять эти строки?

Sure:

  1. Первая строка объявляет постоянное значение, которое однозначно идентифицирует горячую клавишу, установленную с помощью функции RegisterHotKey. Более конкретно, он соответствует параметру id функции. Вы передали его при первом вызове.

  2. Эта проверка в оконной процедуре (WndProc), чтобы увидеть, если сообщение (Msg), который находится в процессе обработки является WM_HOTKEY message. Сообщение WM_HOTKEY автоматически отправляется в ваше окно, когда нажата горячая клавиша, которую вы зарегистрировали с помощью функции RegisterHotKey.

    Вы действительно не должны использовать магическое число 0x0312, потому что вы не единственный, кто не знает, что это значит. Вместо этого, определить константу и использовать это вместо того, чтобы:

    const int WM_HOTKEY = 0x0312; 
    m.Msg == WM_HOTKEY 
    

    Вторая часть этого условного теста (часть после &&) проверяет wParam поле сообщения, чтобы увидеть, если горячая клавиша, которая была нажата была одна вы зарегистрировались. Помните, что MYACTION_HOTKEY_ID - это уникальный идентификатор вашей горячей клавиши. Документация сообщений WM_HOTKEY сообщает нам, что проверка wParam заключается в том, как мы определяем, какая горячая клавиша была нажата.

  3. Это вызывает процедуру окна базового класса. Другими словами, то, что вы сделали, переопределено виртуальным методом WndProc, что позволяет добавить дополнительный код (ваша обработка WM_HOTKEY). Когда вы закончите с вашей дополнительной логикой, вы хотите продолжить логику базового класса, поэтому пересылаете сообщение.

+2

+1 для четких объяснений. – Otiel

+0

Бла, объяснение становится еще яснее, когда я на самом деле запускаю код для себя. Ответ обновлен. :-) –

Смежные вопросы