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



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



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



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



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



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

771   9  

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. переключатель элемент сообщения tab
  5. выберите Очистить Все
  6. выберите WM_HOTKEY в списке, или проверьте клавиатура на Группы Сообщение (если вы в порядке с более потенциальным шумом)
  7. выберите ОК
  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 был задан кем-то, связанным с этим вопросом, но я думал, что все равно свяжусь с ним, чтобы сохранить их вместе. Нить выглядит очень интригующей, но я подозреваю, что некоторые глубокие погружения спелеологии должны были бы произойти, чтобы понять это без доступа к MS internals.

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

Edit: очевидно, я ошибался в этом. 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. Вы не сможете знать все ключи верно с места в карьер, но как они были нажаты можно легко выяснить, какое приложение использует их. Если вы сохраняете свои результаты на диске и перезагружаете каждый раз, когда приложение монитора запускается, вы можете увеличить производительность своего приложения с течением времени.

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

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

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

Comments

    Ничего не найдено.