Узнайте, в каком процессе зарегистрирована глобальная горячая клавиша? (Windows API) - PullRequest
97 голосов
/ 06 мая 2009

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

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

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

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

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

Ответы [ 8 ]

27 голосов
/ 27 апреля 2017

Одним из возможных способов является использование инструмента Visual Studio Spy ++ .

Попробуйте:

  1. Запустите инструмент (для меня это C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. В строке меню выберите Шпион -> Журнал сообщений ... (или нажмите Ctrl + M )
  3. Отметьте Все окна в системе в Дополнительные окна Рамка
  4. Переключиться на вкладку Сообщения
  5. Нажмите кнопку Очистить все
  6. Выберите WM_HOTKEY в списке или отметьте Клавиатура в Группы сообщений (если вы в порядке с большим количеством потенциальных шумов)
  7. Нажмите кнопку OK
  8. Нажмите соответствующую горячую клавишу (например, Win + R )
  9. Выберите строку WM_HOTKEY в окне Сообщения (Все окна) , щелкните правой кнопкой мыши и выберите Свойства ... в контекстном меню
  10. В диалоговом окне Свойства сообщения щелкните ссылку Описатель окна (это будет дескриптор окна, получившего сообщение)
  11. Нажмите кнопку Синхронизировать в диалоговом окне Свойства окна . Это покажет окно в главном дереве Spy ++.
  12. В диалоговом окне Свойства окна выберите вкладку Процесс
  13. Нажмите на ссылку Идентификатор процесса . Это покажет вам процесс (В моем Win + R case: EXPLORER)
19 голосов
/ 20 мая 2009

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

Я нашел этот пример создания клавиатуры (в 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;

Если у вас есть доступ к Safari Books Online , есть хороший раздел о работе с ярлыками / ссылками оболочки в Руководстве разработчика Borland Delphi 6 от Steve Teixeira и Xavier Пачеко. Мой пример выше - отрубленная версия оттуда и этот сайт .

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

9 голосов
/ 11 мая 2009

После некоторых исследований выяснилось, что вам нужно получить доступ к внутренней структуре, которую 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.

3 голосов
/ 19 мая 2009

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

Редактировать: Очевидно, я был неправ в этом. MSDN имеет больше информации:

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

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

2 голосов
/ 08 марта 2011

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

1 голос
/ 07 мая 2009

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

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

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

(отказ от ответственности: он был в моих закладках, я не пробовал и не проверял)

0 голосов
/ 27 декабря 2014

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

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

0 голосов
/ 07 мая 2009

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

...