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


114

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

За відсутності прямого API, чи може існувати обхідний шлях? Windows підтримує обробку, пов’язану з кожною зареєстрованою гарячою клавішею - це трохи нерозумно, що не може бути ніякої можливості отримати цю інформацію.

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

Це нічого критичного, але я часто бачив запити щодо такої функціональності, і я став жертвою програм, які реєструють гарячі клавіші, навіть не розкриваючи їх де-небудь в інтерфейсі або в документах.

(Робота в Delphi, і не більше, ніж учень у WinAPI, будь ласка, будь ласка.)

Відповіді:


20

Ваше запитання викликало мій інтерес, тому я трохи копав, і, на жаль, не маю належної відповіді для вас, я думав, що поділюсь тим, що маю.

Я знайшов цей приклад створення гачка для клавіатури (у 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 Стіва Тейшейри та Ксав'єра Пачеко є хороший розділ про роботу з ярликами / оболонками . Мій приклад вище - це врізана версія звідти та з цього сайту .

Сподіваюся, що це допомагає!


59

Один із можливих способів - використовувати інструмент 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. Натисніть кнопку ОК
  8. Натисніть відповідну гарячу клавішу ( Win+ R, наприклад)
  9. Виберіть WM_HOTKEYрядок у вікні Повідомлення (Усі Windows) , клацніть правою кнопкою миші та виберіть Властивості ... у контекстному меню
  10. У діалоговому вікні " Властивості повідомлення" натисніть посилання " Ручка вікна " (це буде ручка для вікна, яке отримало повідомлення)
  11. Натисніть кнопку " Синхронізувати" у діалоговому вікні "Властивості вікна". Це покаже вікно в головному режимі перегляду вікон Spy ++.
  12. У діалоговому вікні "Властивості вікна" виберіть " Процес" вкладку "
  13. Клацніть посилання Ідентифікатор процесу . Це покаже вам процес (У моєму Win+ Rвипадку EXPLORER:)

6
Чудова відповідь! Лише зауважте, що 64-розрядна версія Spy ++ ловить лише повідомлення для 64-бітних програм , тому якщо ви не бачите WM_HOTKEYповідомлення в журналі повідомлень після натискання швидкої клавіші, можливо, вам доведеться запустити 32-бітну версію Spy ++ .
David Ferenczy Rogožan

ДУЖЕ ДЯКУЮ!!! Я в основному відмовився від використання деяких ярликів, поки не знайшов цього.
thewindev

3
На кроці 8 він не запитує гарячу клавішу, вікно повідомлень залишається порожнім після натискання будь-якої гарячої клавіші. Використовуються 32 та 64-бітні версії від github.com/westoncampbell/SpyPlusPlus (у Windows 10).
CoolMind

9

Після деяких досліджень виявляється, що вам потрібно буде отримати доступ до внутрішньої структури, яку 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;
}

Я припускаю, що цю тему для системних сімей запитав хтось, хто має відношення до цього питання, але я подумав, що все-таки я зв’яжусь із цим, щоб утримати їх разом. Нитка виглядає дуже інтригуюче, але я підозрюю, що для того, щоб зрозуміти це, не маючи доступу до внутрішніх служб МС, знадобиться якесь глибоке занурення.


3

Ви можете спробувати перерахувати всі вікна за допомогою EnumWindows, а потім у зворотному дзвінку відправити WM_GETHOTKEY у кожне вікно.

Редагувати: Я, мабуть, помилявся в цьому. MSDN має більше інформації:

WM_HOTKEY не пов'язаний із гарячими клавішами WM_GETHOTKEY та WM_SETHOTKEY. Повідомлення WM_HOTKEY надсилається для загальних гарячих клавіш, тоді як повідомлення WM_SETHOTKEY та WM_GETHOTKEY стосуються гарячих клавіш активації вікна.

Примітка. Ось програма, яка передбачає функціональність, яку ви шукаєте. Ви можете спробувати розкласти його.


3
Посилання на програму зараз повністю порушено. Яка програма це була? Я так багато разів хотів би розібратися, яка програма зареєструвала мої гарячі клавіші, бо раптом вони більше не працюють або неприємні нові речі.
Джеймс Олтманс

(Часто машина зворотного зв'язку може допомогти у випадку зникнення веб-сторінки, але тут вона відображає лише дзеркальне відображення 404 Not Found: http://web.archive.org/web/*/tds.diamondcs.com.au/dse/ виявлення / hotkeys.php )
Аарон Тома

2

Це, здається, вам багато говорить: http://hkcmdr.anymania.com/help.html


1
Робить це? DLL маскується під драйвер? Функція DLL, експортована як hooвикористання SetWindowHookExдля встановлення двох гаків, одного WH_KEYBOARD_LLта одного WH_GETMESSAGE... решта має бути досить задокументовано на MSDN.
0xC0000022L

Не використовуйте цей додаток для Windows 8 або 10.
Джефф Ланге

1

Ще одна нитка згадує глобальний гачок клавіатури на рівні NT:

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

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

(відмова від відповідальності: я мав це у своїх закладках, насправді не пробував / перевіряв)


0

Я знаю, що ви можете перехопити потік повідомлень у будь-якому вікні вашого власного процесу - як ми звикли називати підкласифікацію в VB6. (Хоча я не пам’ятаю цю функцію, можливо, SetWindowLong?) Я не впевнений, чи можете ви це зробити для Windows за межами власного процесу. Але заради цієї публікації припустимо, що ви знайдете спосіб це зробити. Тоді ви можете просто перехопити повідомлення для всіх вікон верхнього рівня, відстежувати повідомлення WM_HOTKEY. Ви не зможете дізнатись усі клавіші безпосередньо з кажана, але, натиснувши їх, ви могли легко зрозуміти, яка програма їх використовує. Якщо ви зберігатимете свої результати на диску та перезавантажуватимете щоразу, коли програма монітора запускалася, ви могли з часом підвищити продуктивність вашої програми.


-1

Це не точно відповідає частині питання, що стосується API Windows, але воно відповідає частині питання, що стосується списку глобальних гарячих клавіш та програм, які "володіють ними".

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


4
встановив його, і він діяв як вірус, хоча б програма з торговим центром, як поганий жарт. Відкривання всіх видів вікон, активація голосового наратора тощо
Фліон

3
@Flion: Дивіться дискусію на сайті superuser.com/a/191090/3617 . В основному деякі утиліти швидкої клавіші працюють за допомогою зондування кожної можливої ​​комбінації клавіш. У Windows 8+ (і в меншій мірі в Windows 7) ця методика зондування запускає кожну комбінацію клавіш, а не просто запитувати її.
Брайан

@Flion FWIW, я використовував його на Win7 з успіхом. Але якщо я правильно розумію Брайана, це може не працювати так з пізнішими версіями, і від того, наскільки добре він працює, також може залежати від визначених спеціальних гарячих клавіш.
Герхард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.