Domanda

Per quanto ho potuto 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 falso, ma non chi "possiede" il tasto di scelta rapida.

In assenza di un'API diretta, potrebbe esserci una rotonda? 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 brutta cosa da fare, poiché l'invio di tasti di scelta rapida innescherebbe ogni tipo di attività potenzialmente indesiderata da vari programmi.

Non è nulla di critico, ma ho visto frequenti richieste di tale funzionalità e sono stato vittima di applicazioni che registrano tasti di scelta rapida senza nemmeno rivelarlo in nessuna parte dell'interfaccia utente o dei documenti.

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

È stato utile?

Soluzione

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

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

È una DLL con una chiamata a SetWindowsHookEx che 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 sinistro a destra, ecc. Un'app semplice chiama quindi la DLL e riporta i risultati in base a 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 fosse possibile ottenere l'handle dell'applicazione che ha inviato i tasti premuti, è possibile 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 esaminando i tasti di scelta rapida 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à, pertanto potrebbe non restituire molto. Se sei interessato a quella rotta, Delphi ha accesso all'interfaccia COM IShellLink che puoi usare per caricare un collegamento da 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'è un buona sezione su come lavorare con scorciatoie / collegamenti shell nella Guida per gli sviluppatori di Borland Delphi 6 di Steve Teixeira e Xavier Pacheco. Il mio esempio sopra è una versione macellata da lì e questo sito .

Spero che ti aiuti!

Altri suggerimenti

Un modo possibile è utilizzare Visual Studio tool Spy ++ .

Provalo:

  1. Esegui lo strumento (per me è in C: \ Programmi (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 Windows aggiuntivo frame
  4. Passa alla scheda Messaggi
  5. Fai clic sul pulsante Cancella tutto
  6. Seleziona WM_HOTKEY nella casella di riepilogo, oppure seleziona Tastiera in Gruppi di messaggi (se stai bene con più rumore potenziale)
  7. Fai clic sul pulsante OK
  8. Premi il tasto di scelta rapida in questione ( Win + R , ad esempio)
  9. Seleziona la riga WM_HOTKEY nella finestra Messaggi (tutte le finestre) , fai clic con il pulsante destro del mouse e seleziona Proprietà ... nel menu di scelta rapida
  10. Nella finestra di dialogo Proprietà messaggio , fai clic sul link Maniglia della finestra (questa sarà la maniglia della finestra che ha ricevuto il messaggio)
  11. Fai clic sul pulsante Sincronizza nella finestra di dialogo Proprietà finestra . Questo mostrerà la finestra nella finestra principale della finestra Spy ++.
  12. Nella finestra di dialogo Proprietà finestra , selezionare la scheda Elaborazione
  13. Fai clic sul link ID processo . Questo ti mostrerà il processo (Nel mio caso Win + R : EXPLORER )

Dopo alcune ricerche, sembra che dovresti avere accesso alla struttura interna utilizzata da MS per memorizzare i tasti di scelta rapida. ReactOS ha un'implementazione in clean room che implementa la chiamata GetHotKey ripetendo un elenco interno ed estraendo il tasto di scelta rapida che corrisponde ai parametri della chiamata.

A seconda di quanto è vicina l'implementazione di ReactOS 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 mi è stato chiesto da qualcuno collegato a questo domanda, ma ho pensato di collegarmi comunque per tenere uniti i due. Il thread sembra molto intrigante, ma sospetto che occorrerebbe qualche spelunking per immersioni profonde per capirlo senza avere accesso agli interni della SM.

Dalla parte superiore della mia testa, potresti provare a enumerare tutte le finestre con EnumWindows, quindi nel callback, invia WM_GETHOTKEY a ciascuna finestra.

Modifica: evidentemente mi sbagliavo. MSDN contiene ulteriori 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: Qui è un programma che pretende di avere la funzionalità stai cercando. Potresti provare a decompilarlo.

Questo sembra dirti molto: http://hkcmdr.anymania.com/help.html

Un altro thread menziona un hook di tastiera globale di livello NT:

Riassegna / ignora tasto di scelta rapida (Win + L) per bloccare Windows

forse puoi ottenere l'handle del processo che ha chiamato l'hook in quel modo, che puoi quindi risolvere con il nome del processo

(dichiarazione di non responsabilità: l'avevo nei miei segnalibri, non l'ho mai provato / testato)

So che puoi intercettare il flusso di messaggi in qualsiasi finestra all'interno del tuo processo, quello che chiamavamo sottoclasse in VB6. (Anche se non ricordo la funzione, forse SetWindowLong?) Non sono sicuro che sia possibile farlo per Windows al di fuori del proprio 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 livello superiore, monitorare il messaggio WM_HOTKEY. Non sarai in grado di conoscere tutti i tasti fin dall'inizio, ma man mano che li premi, potresti facilmente capire quale applicazione li stava usando. Se i risultati sono stati persistenti su disco e ricaricati ogni volta che è stata eseguita l'applicazione di monitoraggio, è possibile aumentare le prestazioni dell'applicazione nel tempo.

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 "possiedono" loro.

L'Explorer di tasti di scelta rapida gratuito su http://hkcmdr.anymania.com/ mostra un elenco di tutti i tasti di scelta rapida e le 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top