Scopri quale processo ha registrato un tasto di scelta rapida globale? (API di Windows)


114

Per quanto sono stato in grado di scoprire, Windows non offre una funzione API per dire quale applicazione ha registrato un tasto di scelta rapida globale (tramite RegisterHotkey). Posso solo scoprire che un tasto di scelta rapida è registrato se RegisterHotkey restituisce false, ma non chi "possiede" il tasto di scelta rapida.

In assenza di un'API diretta, potrebbe esserci una via indiretta? Windows mantiene l'handle associato a ciascun tasto di scelta rapida registrato: è un po 'esasperante che non ci sia modo di ottenere queste informazioni.

Esempio di qualcosa che probabilmente non funzionerebbe: inviare (simulare) un tasto di scelta rapida registrato, quindi intercettare il messaggio di tasto di scelta rapida che Windows invierà al processo che lo ha registrato. Innanzitutto, non credo che l'intercettazione del messaggio rivelerebbe l'handle della finestra di destinazione. In secondo luogo, anche se fosse possibile, sarebbe una cosa negativa, poiché l'invio di tasti di scelta rapida attiverebbe tutti i tipi di attività potenzialmente indesiderate da vari programmi.

Non è niente di critico, ma ho visto frequenti richieste di tale funzionalità e io stesso sono stato vittima di applicazioni che registrano i tasti di scelta rapida senza nemmeno rivelarli da nessuna parte nell'interfaccia utente o nei documenti.

(Lavorando in Delphi e non più di un apprendista presso WinAPI, per favore sii gentile.)

Risposte:


20

La tua domanda ha suscitato il mio interesse, quindi ho scavato un po 'e mentre, purtroppo, non ho una risposta adeguata per te, ho pensato di condividere ciò che ho.

Ho trovato questo esempio di creazione di hook da tastiera (in Delphi) scritto nel 1998, ma è compilabile in Delphi 2007 con un paio di modifiche.

È una DLL con una chiamata a SetWindowsHookExche passa attraverso una funzione di callback, che può quindi intercettare i tasti premuti: in questo caso, sta armeggiando con loro per divertimento, cambiando il cursore da sinistra a destra, ecc. Una semplice app quindi chiama la DLL e riporta indietro i suoi risultati sono basati su un evento TTimer. Se sei interessato, posso pubblicare il codice basato su Delphi 2007.

È ben documentato e commentato e potenzialmente potresti usarlo come base per capire dove sta andando la pressione di un tasto. Se riuscissi a ottenere l'handle dell'applicazione che ha inviato i tasti, potresti rintracciarlo in quel modo. Con quella maniglia sarai in grado di ottenere le informazioni di cui hai bisogno abbastanza facilmente.

Altre app hanno provato a determinare i tasti di scelta rapida passando attraverso le scorciatoie poiché possono contenere un tasto di scelta rapida, che è solo un altro termine per tasto di scelta rapida. Tuttavia, la maggior parte delle applicazioni non tende a impostare questa proprietà, quindi potrebbe non restituire molto. Se sei interessato a quel percorso, Delphi ha accesso all'interfaccia IShellLinkCOM che potresti usare per caricare un collegamento e ottenere il suo tasto di scelta rapida:

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;

Se hai accesso a Safari Books Online , c'è una buona sezione su come lavorare con scorciatoie / collegamenti shell nella Borland Delphi 6 Developer's Guide di Steve Teixeira e Xavier Pacheco. Il mio esempio sopra è una versione macellata da lì e da questo sito .

Spero che aiuti!


59

Un modo possibile è utilizzare lo strumento di Visual Studio Spy ++ .

Provalo:

  1. Esegui lo strumento (per me, è a C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. Nella barra dei menu, seleziona Spia -> Registra messaggi ... (o premi Ctrl+ M)
  3. Seleziona Tutte le finestre nel sistema nel riquadro Finestre aggiuntive
  4. Passa alla scheda Messaggi
  5. Fare clic sul pulsante Cancella tutto
  6. Seleziona WM_HOTKEYnella casella di riepilogo o seleziona Tastiera in Gruppi di messaggi (se stai bene con più rumore potenziale)
  7. Fare clic sul pulsante OK
  8. Premere il tasto di scelta rapida in questione ( Win+ R, ad esempio)
  9. Selezionare la WM_HOTKEYriga nella finestra Messaggi (tutte le finestre) , fare clic con il tasto destro e selezionare Proprietà ... nel menu contestuale
  10. Nella finestra di dialogo Proprietà messaggio , fare clic sul collegamento Maniglia della finestra (questa sarà la maniglia della finestra che ha ricevuto il messaggio)
  11. Fare clic sul pulsante Sincronizza nella finestra di dialogo Proprietà finestra. Questo mostrerà la finestra nella visualizzazione ad albero della finestra principale di Spy ++.
  12. Nella finestra di dialogo Proprietà finestra, seleziona la scheda Processo
  13. Fare clic sul collegamento ID processo . Questo ti mostrerà il processo (nel mio Win+ Rcaso EXPLORER:)

6
Bella risposta! Solo una nota che la versione a 64 bit di Spy ++ cattura solo i messaggi per le applicazioni a 64 bit , quindi se non vedi il WM_HOTKEYmessaggio nel registro dei messaggi dopo aver premuto il tasto di scelta rapida, potresti dover eseguire la versione a 32 bit di Spy ++ .
David Ferenczy Rogožan

GRAZIE MILLE!!! Fondamentalmente ho rinunciato a usare alcune scorciatoie finché non l'ho trovato.
thewindev

3
Nel passaggio 8 non richiede hotkey, la finestra dei messaggi rimane vuota dopo aver premuto qualsiasi hotkey. Utilizzate versioni a 32 e 64 bit da github.com/westoncampbell/SpyPlusPlus (in Windows 10).
CoolMind

9

Dopo alcune ricerche, sembra che sia necessario accedere alla struttura interna che MS utilizza per memorizzare i tasti di scelta rapida. ReactOS ha un'implementazione della stanza pulita che implementa la GetHotKeychiamata iterando un elenco interno ed estraendo il tasto di scelta rapida che corrisponde ai parametri della chiamata.

A seconda di quanto l'implementazione di ReactOS sia vicina all'implementazione di MS, potresti essere in grado di curiosare nella memoria per trovare la struttura, ma è sopra la mia testa ...

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

Presumo che questo thread su sysinternals sia stato chiesto da qualcuno correlato a questa domanda, ma ho pensato di collegarmi comunque ad esso per tenere insieme i due. Il thread sembra molto intrigante, ma sospetto che sarebbe necessario eseguire un po 'di speleologia profonda per capirlo senza accesso agli interni di MS.


3

Dalla parte superiore della mia testa, potresti provare a enumerare tutte le finestre con EnumWindows, quindi nella richiamata, inviare WM_GETHOTKEY a ciascuna finestra.

Modifica: apparentemente mi sbagliavo su questo. MSDN ha più informazioni:

WM_HOTKEY non è correlato ai tasti di scelta rapida WM_GETHOTKEY e WM_SETHOTKEY. Il messaggio WM_HOTKEY viene inviato per i tasti di scelta rapida generici mentre i messaggi WM_SETHOTKEY e WM_GETHOTKEY si riferiscono ai tasti di scelta rapida di attivazione della finestra.

Nota: ecco un programma che pretende di avere le funzionalità che stai cercando. Potresti provare a decompilarlo.


3
Il collegamento al programma è ora completamente interrotto. Che programma era quello? Ci sono così tante volte che mi piacerebbe capire quale programma ha registrato i miei tasti di scelta rapida perché improvvisamente non funzionano più o fanno cose nuove fastidiose.
James Oltmans

(Spesso, la Wayback Machine può aiutare in caso di scomparsa di una pagina web, ma qui ha anche rispecchiato solo un 404 Not Found: http://web.archive.org/web/*/tds.diamondcs.com.au/dse/ detection / hotkeys.php )
Aaron Thoma



0

So che puoi intercettare il flusso di messaggi in qualsiasi finestra all'interno del tuo processo, ciò che chiamavamo sottoclasse in VB6. (Anche se non ricordo la funzione, forse SetWindowLong?) Non sono sicuro se puoi farlo per Windows al di fuori del tuo processo. Ma per il bene di questo post, supponiamo che tu trovi un modo per farlo. Quindi puoi semplicemente intercettare i messaggi per tutte le finestre di primo livello, monitorare il messaggio WM_HOTKEY. Non saresti in grado di conoscere tutti i tasti fin dall'inizio, ma mentre venivano premuti potresti facilmente capire quale applicazione li stava usando. Se i risultati sono stati conservati su disco e ricaricati ogni volta che è stata eseguita l'applicazione di monitoraggio, è possibile aumentare le prestazioni dell'applicazione nel tempo.


-1

Questo non risponde esattamente alla parte della domanda che riguarda l'API di Windows, ma risponde alla parte della domanda che riguarda un elenco di tasti di scelta rapida globali e le applicazioni che li "possiedono".

Hotkey Explorer gratuito su http://hkcmdr.anymania.com/ mostra un elenco di tutti i tasti di scelta rapida globali e delle applicazioni che li possiedono. Questo mi ha solo aiutato a capire perché un tasto di scelta rapida specifico dell'applicazione ha smesso di funzionare e come risolverlo (riconfigurando il tasto di scelta rapida globale registrato nell'app che lo aveva registrato), in pochi secondi.


4
lo ha installato e ha agito come un virus almeno un programma con mall-intend, come un brutto scherzo. Apertura di tutti i tipi di finestre, attivazione del voice narator, ecc.
Flion

3
@Flion: vedere la discussione su superuser.com/a/191090/3617 . Fondamentalmente, alcune utility di tasti di scelta rapida funzionano esaminando ogni possibile combinazione di tasti. Su Windows 8+ (e in misura minore su Windows 7), questa tecnica di sondaggio attiva ogni combinazione di tasti, invece di limitarsi a interrogarla.
Brian

@Flion FWIW, l'ho usato con successo su Win7. Ma se capisco correttamente Brian, questo potrebbe non funzionare anche con le versioni successive e il modo in cui funziona potrebbe dipendere anche dai tasti di scelta rapida personalizzati definiti.
Gerhard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.