Узнайте, какой процесс зарегистрировал глобальную горячую клавишу? (Windows API)

насколько я смог узнать, Windows не предлагает функцию API, чтобы сообщить, какое приложение зарегистрировало глобальную горячую клавишу (через RegisterHotkey). Я могу только узнать, что горячая клавиша зарегистрирована, если RegisterHotkey возвращает false, но не кто "владеет" горячей клавишей.

в отсутствие прямого API, может ли быть окольный путь? Windows поддерживает дескриптор, связанный с каждой зарегистрированной горячей клавишей - это немного сводит с ума, что не должно быть никакого способа добраться эта информация.

пример чего-то, что, вероятно, не будет работать: отправить (имитировать) зарегистрированную горячую клавишу, а затем перехватить сообщение горячей клавиши Windows отправит в процесс, который зарегистрировал его. Во-первых, я не думаю, что перехват сообщения покажет дескриптор окна назначения. Во-вторых, даже если бы это было возможно, это было бы плохо, так как отправка горячих клавиш вызовет всевозможные потенциально нежелательные действия из различных программ.

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

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

9 ответов


Я нашел это пример создания клавиатуры крюк (в Delphi) написано в 1998 году, но компилируется в Delphi 2007 с парой твиков.

- Это DLL с вызовом SetWindowsHookEx, который проходит через функцию обратного вызова, которая затем может перехватывать нажатия клавиш: в данном случае это мастерить с ними для удовольствия, меняя левый курсор на правый и т. д. Затем простое приложение вызывает DLL и сообщает о своих результатах на основе события TTimer. Если вам интересно, я могу опубликовать код на основе Delphi 2007.

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

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

uses ShlObj, ComObj, ShellAPI, ActiveX, CommCtrl;

procedure GetShellLinkHotKey;
var
  LinkFile : WideString;
  SL: IShellLink;
  PF: IPersistFile;

  HotKey : Word;
  HotKeyMod: Byte;
  HotKeyText : string;
begin
  LinkFile := 'C:\Temp\Temp.lnk';

  OleCheck(CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, SL));

  // The IShellLink implementer must also support the IPersistFile
  // interface. Get an interface pointer to it.
  PF := SL as IPersistFile;

  // Load file into IPersistFile object
  OleCheck(PF.Load(PWideChar(LinkFile), STGM_READ));

  // Resolve the link by calling the Resolve interface function.
  OleCheck(SL.Resolve(0, SLR_ANY_MATCH or SLR_NO_UI));

  // Get hotkey info
  OleCheck(SL.GetHotKey(HotKey));

  // Extract the HotKey and Modifier properties.
  HotKeyText := '';
  HotKeyMod := Hi(HotKey);

  if (HotKeyMod and HOTKEYF_ALT) = HOTKEYF_ALT then
    HotKeyText := 'ALT+';
  if (HotKeyMod and HOTKEYF_CONTROL) = HOTKEYF_CONTROL then
    HotKeyText := HotKeyText + 'CTRL+';
  if (HotKeyMod and HOTKEYF_SHIFT) = HOTKEYF_SHIFT then
    HotKeyText := HotKeyText + 'SHIFT+';
  if (HotKeyMod and HOTKEYF_EXT) = HOTKEYF_EXT then
    HotKeyText := HotKeyText + 'Extended+';

  HotKeyText := HotKeyText + Char(Lo(HotKey));

  if (HotKeyText = '') or (HotKeyText = #0) then
    HotKeyText := 'None';

  ShowMessage('Shortcut Key - ' + HotKeyText);
end;

Если у вас есть доступ к Сафари Книги Онлайн, есть хороший раздел о работе с ярлыками / shell links в руководстве разработчика Borland Delphi 6 Стива Тейшейры и Ксавье Пачеко. Мой пример выше-разделанная версия оттуда и этот сайт.

надеюсь, что это поможет!


один из возможных способов-использовать Visual Studio tool Spy++.

попробуйте:

  1. запустите инструмент (для меня это в C:\Program Files (x86)\Microsoft Visual Studio17\Community\Common7\Tools\spyxx_amd64.exe)
  2. в строке меню выберите шпион ->сообщения журнала... (или нажмите Ctrl + M)
  3. Регистрация все окна в системе на Дополнительные Окна рама
  4. переключатель the сообщения tab
  5. выберите Очистить Все
  6. выберите WM_HOTKEY в списке или отметьте клавиатура на Группы Сообщение (если вы в порядке с более потенциальным шумом)
  7. выберите OK
  8. нажмите горячую клавишу в вопрос ( Win + R, например)
  9. выберите WM_HOTKEY строка Сообщения (Все Windows) окно, щелкните правой кнопкой мыши и выберите свойства... в контекстном меню
  10. на Свойства Сообщение диалоговое окно, нажмите кнопку на Свойства Окне диалог. Это покажет окно в главном окне Spy++ treeview.
  11. на Свойства Окне диалоговое окно выберите

после некоторых исследований кажется, что вам нужно получить доступ к внутренней структуре, которую MS использует для хранения горячих клавиш. ReactOS имеет реализацию чистой комнаты, которая реализует GetHotKey вызов путем итерации внутреннего списка и извлечения горячей клавиши, которая соответствует параметрам вызова.

в зависимости от того, насколько близка реализация ReactOS к реализации MS, вы можете рыться в памяти, чтобы найти структуру, но это выше моей головы...

BOOL FASTCALL
GetHotKey (UINT fsModifiers,
           UINT vk,
           struct _ETHREAD **Thread,
           HWND *hWnd,
           int *id)
{
   PHOT_KEY_ITEM HotKeyItem;

   LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
   {
      if (HotKeyItem->fsModifiers == fsModifiers &&
            HotKeyItem->vk == vk)
      {
         if (Thread != NULL)
            *Thread = HotKeyItem->Thread;

         if (hWnd != NULL)
            *hWnd = HotKeyItem->hWnd;

         if (id != NULL)
            *id = HotKeyItem->id;

         return TRUE;
      }
   }

   return FALSE;
}

предполагаю этот поток на sysinternals был задан кем-то, связанным с этим вопросом, но я думал, что все равно свяжусь с ним, чтобы держать их вместе. Нить выглядит очень интригующе, но я подозреваю, что некоторые глубокое погружение погружение должно произойти, чтобы понять это без доступа к МС внутренности.


с моей головы вы можете попробовать перечислить все окна с помощью EnumWindows, а затем в обратном вызове отправить WM_GETHOTKEY в каждое окно.

изменить: Apparrently я ошибался. MSDN дополнительная информация:

WM_HOTKEY не связан с горячими клавишами WM_GETHOTKEY и WM_SETHOTKEY. Сообщение WM_HOTKEY отправляется для общих горячих клавиш, а сообщения WM_SETHOTKEY и WM_GETHOTKEY относятся к активации окна hot ключи.

Примечание: здесь это программа, претендующая на функциональность, которую вы ищете. Вы можете попробовать декомпилировать его.


Это, кажется, говорит вам много: http://hkcmdr.anymania.com/help.html


другой поток упоминает глобальный крюк клавиатуры уровня NT:

повторно назначить / переопределить горячую клавишу (Win + L) для блокировки windows

может быть, вы можете получить дескриптор процесса, который вызвал крючок таким образом, который вы можете решить для имени процесса

(оговорка: у меня в мои закладки, не пробовал/проверял)


Я знаю, что вы можете перехватить поток сообщений в любом окне в своем собственном процессе - то, что мы называли подклассами в VB6. (Хотя я не помню функции, возможно, SetWindowLong?) Я не уверен, что вы можете сделать это для windows вне своего собственного процесса. Но ради этого поста, предположим, вы найдете способ сделать это. Затем вы можете просто перехватывать сообщения для всех окон верхнего уровня, следить за сообщением WM_HOTKEY. Ты не сможешь правильно знать все ключи. с места в карьер, но как они были нажаты можно легко выяснить, какое приложение использует их. Если результаты сохраняются на диске и перезагружаются при каждом запуске приложения monitor, можно повысить производительность приложения со временем.


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

бесплатный проводник горячих клавиш в http://hkcmdr.anymania.com/ показывает список всех глобальных горячих клавиш и приложений, которым они принадлежат. Это просто помогло мне понять, почему ярлык приложения перестал работать и как его исправить (по перенастройка зарегистрированной глобальной горячей клавиши в приложении, которое было зарегистрировано), в течение нескольких секунд.


Я не был жестким пользователем windows в течение нескольких лет (я переключился на Mac). Но я клялся Процесс Explorer чтобы узнать, какой процесс использует конкретный файл, который я пытался удалить. Может быть, это поможет выяснить, какой процесс использует Горячий Ключ?