Dowiedz się, w jakim procesie zarejestrowano globalny Skrót klawiszowy? (Windows API)

O ile udało mi się dowiedzieć, Windows nie oferuje funkcji API, która aplikacja zarejestrowała globalny klucz skrótu (poprzez RegisterHotkey). Mogę tylko dowiedzieć się, że hotkey jest zarejestrowany, jeśli RegisterHotkey zwraca false, ale nie kto "jest właścicielem" hotkey.

W przypadku braku bezpośredniego API, może być droga okrężna? Windows utrzymuje uchwyt związany z każdym zarejestrowanym skrótem klawiszowym - to trochę szalone, że nie powinno być sposobu na uzyskanie tego informacje.

Przykład czegoś, co prawdopodobnie nie zadziała: wyślij (symuluj) zarejestrowany Skrót klawiszowy, a następnie przechwyć wiadomość o skrócie klawiszowym, którą Windows wyśle do procesu, który go zarejestrował. Po pierwsze, nie sądzę, aby przechwycenie wiadomości ujawniło uchwyt okna docelowego. Po drugie, nawet jeśli byłoby to możliwe, byłoby to złe, ponieważ wysyłanie skrótów klawiszowych powodowałoby wszelkiego rodzaju potencjalnie niechciane działania z różnych programów.

To nic krytycznego, ale mam widziałem częste prośby o taką funkcjonalność, a sam byłem ofiarą aplikacji, które rejestrują skróty klawiszowe, nawet nie ujawniając go w dowolnym miejscu interfejsu użytkownika lub dokumentów.

(Praca w Delphi, a nie więcej niż praktykant w WinAPI, proszę o życzliwość.)

Author: Marek Jedliński, 2009-05-06

9 answers

Twoje pytanie wzbudziło moje zainteresowanie, więc trochę poszperałem i chociaż niestety nie mam dla Ciebie właściwej odpowiedzi, pomyślałem, że podzielę się tym, co mam.

Znalazłem ten przykład tworzenia Hooka klawiatury (w Delphi) napisany w 1998 roku, ale można go skompilować w Delphi 2007 z kilkoma poprawkami.

Jest to biblioteka DLL z wywołaniem SetWindowsHookEx, która przechodzi przez funkcję zwrotną, która może przechwytywać naciski klawiszy: w tym przypadku majstruje z nimi dla Zabawy, zmiana lewego kursora na prawy itd. Prosta aplikacja następnie wywołuje bibliotekę DLL i raportuje jej wyniki na podstawie zdarzenia TTimer. Jeśli jesteś zainteresowany mogę zamieścić kod oparty na Delphi 2007.

Jest dobrze udokumentowany i skomentowany i potencjalnie możesz go użyć jako podstawy do ustalenia, dokąd zmierza naciśnięcie klawisza. Jeśli możesz uzyskać uchwyt aplikacji, która wysłała naciski klawiszy, możesz go wyśledzić w ten sposób. Z tym uchwytem będziesz w stanie uzyskać informacje, których potrzebujesz całkiem łatwo.

Inne aplikacje próbowały określić skróty klawiszowe, przechodząc przez ich skróty, ponieważ mogą zawierać klawisz skrótu, który jest po prostu innym terminem dla skrótu klawiszowego. Jednak większość aplikacji nie ustawia tej właściwości, więc może nie zwracać zbyt wiele. Jeśli jesteś zainteresowany tą trasą, Delphi ma dostęp do interfejsu IShellLink COM, którego możesz użyć do załadowania skrótu i uzyskania jego skrótu klawiszowego:

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;

Jeśli masz dostęp do Safari Books Online , jest dobra sekcja o pracy ze skrótami / linkami do powłoki W Borland Delphi 6 Developer 's Guide autorstwa Steve' a Teixeiry i Xaviera Pacheco. Mój przykład powyżej to zarżnięta wersja stamtąd i Ta strona .

Mam nadzieję, że to pomoże!
 19
Author: Pauk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-21 20:46:53

Jednym z możliwych sposobów jest użycie Visual Studio tool Spy++.

Spróbuj:

  1. uruchom narzędzie (dla mnie jest to w C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. w pasku menu wybierz Spy -> Zaloguj wiadomości... (lub naciśnij Ctrl + M )
  3. Sprawdź wszystkie okna w systemie w ramce dodatkowe okna
  4. Przełącz na zakładkę Wiadomości
  5. kliknij Wyczyść wszystko button
  6. Wybierz WM_HOTKEY w polu listy, lub zaznacz klawiaturę W grupy wiadomości (jeśli nie masz nic przeciwko z większym potencjalnym szumem)
  7. kliknij przycisk OK
  8. naciśnij hotkey (Win + R , na przykład)
  9. wybierz linię WM_HOTKEY w oknie Messages (wszystkie okna), kliknij prawym przyciskiem myszy i wybierz Właściwości ... w menu kontekstowym
  10. w oknie dialogowym właściwości wiadomości kliknij link (będzie to uchwyt dla okna, które otrzymało wiadomość)
  11. kliknij przycisk Synchronizuj w oknie dialogowym właściwości okna. Spowoduje to wyświetlenie okna w głównym drzewie okna Spy++.
  12. w oknie dialogowym właściwości okna wybierz zakładkę proces
  13. Kliknij link ID procesu. To pokaże ci proces (w moim wygrać + R przypadek: EXPLORER)
 17
Author: user995048,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-17 15:05:47

Po pewnych badaniach wydaje się, że będziesz musiał uzyskać dostęp do wewnętrznej struktury, której MS używa do przechowywania skrótów klawiszowych. ReactOS posiada implementację clean room, która implementuje wywołanie GetHotKey poprzez iterację wewnętrznej listy i wyodrębnienie skrótu klawiszowego, który pasuje do parametrów wywołania.

W zależności od tego, jak blisko jest implementacja ReactOS do implementacji MS, możesz być w stanie poszperać w pamięci, aby znaleźć strukturę, ale to ponad moją głowę...

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;
}

I przypuszczać ten wątek na sysinternals został zadany przez kogoś związanego z tym pytaniem, ale pomyślałem, że i tak linkuję do niego, aby utrzymać te dwa razem. Wątek wygląda bardzo intrygująco, ale podejrzewam, że jakiś spelunking nurkowy musiałby się zdarzyć, aby to rozgryźć bez dostępu do wewnętrznych MS.

 8
Author: John Weldon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-05 00:55:08

Poza moją głową, możesz spróbować wyliczyć wszystkie okna za pomocą EnumWindows, a następnie w wywołaniu zwrotnym wysłać WM_GETHOTKEY do każdego okna.

Edit: MSDN ma więcej informacji:

WM_HOTKEY nie jest powiązane z klawiszami skrótu WM_GETHOTKEY i WM_SETHOTKEY. Wiadomość WM_HOTKEY jest wysyłana dla ogólnych skrótów klawiszowych, podczas gdy wiadomości WM_SETHOTKEY i WM_GETHOTKEY odnoszą się do skrótów klawiszowych aktywacji okna.

Uwaga: tutaj {[4] } jest programem rzekomo posiadającym funkcjonalność, której szukasz. Możesz spróbować go dekompilować.

 3
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-19 01:56:44

To chyba wiele ci mówi: http://hkcmdr.anymania.com/help.html

 2
Author: Caveatrob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-08 18:54:31

Kolejny wątek wspomina o globalnym haku klawiatury poziomu NT:

Re-assign / override hotkey (Win + L) to lock windows

Być może uda Ci się uzyskać uchwyt procesu, który wywołał hook w ten sposób, który możesz następnie rozwiązać na nazwę procesu

(zastrzeżenie: miałem go w zakładkach, nie próbowałem/testowałem)

 1
Author: Marco van de Voort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:47

Wiem, że możesz przechwycić strumień wiadomości w dowolnym oknie własnego procesu - co kiedyś nazywaliśmy subclassingiem w VB6. (Choć nie pamiętam funkcji, może SetWindowLong?) Nie jestem pewien, czy możesz to zrobić dla windows poza własnym procesem. Ale ze względu na ten post pozwala założyć, że znajdziesz sposób, aby to zrobić. Następnie możesz po prostu przechwycić wiadomości dla wszystkich okien najwyższego poziomu, monitorować wiadomość WM_HOTKEY. Nie będziesz w stanie znać wszystkich kluczy. od kija, ale gdy zostały naciśnięte, można było łatwo dowiedzieć się, jaka aplikacja ich używała. Jeśli wyniki są zapisywane na dysku i przeładowywane za każdym razem, gdy aplikacja monitor została uruchomiona, można zwiększyć wydajność aplikacji w czasie.

 0
Author: Sam Axe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-07 19:28:25

Nie odpowiada to dokładnie na Część pytania, które dotyczy Windows API, ale odpowiada na Część pytania, które dotyczy listy globalnych skrótów klawiszowych i aplikacji, które je "posiadają".

Darmowy Hotkey Explorer w http://hkcmdr.anymania.com / pokazuje listę wszystkich globalnych skrótów klawiszowych i aplikacji, które są ich właścicielami. To właśnie pomogło mi dowiedzieć się, dlaczego klawisz skrótu specyficzny dla aplikacji przestał działać i jak go naprawić (poprzez ponowną konfigurację zarejestrowany globalny hotkey w aplikacji, która go zarejestrowała), w ciągu kilku sekund.

 -1
Author: Gerhard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-27 17:56:11

Od kilku lat nie jestem twardym użytkownikiem Windowsa (przesiadłem się na Maca). Ale kiedyś przeklinałem Process Explorer, aby dowiedzieć się, jaki proces używa konkretnego pliku, który próbowałem usunąć. Może pomoże to dowiedzieć się, który proces używa skrótu klawiszowego?

 -6
Author: Peter Di Cecco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-07 13:31:29