Découvrez quel processus a enregistré un raccourci clavier global? (API Windows)
Pour autant que j'ai pu le découvrir, Windows n'offre pas de fonction API pour indiquer quelle application a enregistré un raccourci clavier global (via RegisterHotkey). Je ne peux savoir qu'un raccourci clavier est enregistré si RegisterHotkey renvoie false, mais pas qui "possède" le raccourci clavier.
En l'absence d'une API directe, pourrait-il y avoir un moyen détourné? Windows maintient le handle associé à chaque raccourci enregistré-c'est un peu exaspérant qu'il ne devrait y avoir aucun moyen d'y arriver information.
Exemple de quelque chose qui ne fonctionnerait probablement pas: envoyer (simuler) un raccourci clavier enregistré, puis intercepter le message de raccourci que Windows enverra au processus qui l'a enregistré. Tout d'abord, je ne pense pas que l'interception du message révélerait le handle de la fenêtre de destination. Deuxièmement, même si cela était possible, ce serait une mauvaise chose à faire, car l'envoi de raccourcis clavier déclencherait toutes sortes d'activités potentiellement indésirables de divers programmes.
Ce n'est rien de critique, mais j'ai vu des demandes fréquentes pour une telle fonctionnalité, et j'ai moi-même été victime d'applications qui enregistrent des raccourcis clavier sans même les divulguer n'importe où dans L'interface utilisateur ou les documents.
(travaillant à Delphes, et pas plus qu'un apprenti chez WinAPI, soyez gentil.)
9 réponses
Votre question a piqué mon intérêt, alors j'ai fait un peu de creuser et tandis que, malheureusement, je n'ai pas de réponse appropriée pour vous, j'ai pensé partager ce que j'ai.
J'ai trouvé cet exemple de création de crochet de clavier (en Delphi) écrit en 1998, mais est compilable en Delphi 2007 avec quelques réglages.
C'est une DLL avec un appel à SetWindowsHookEx
qui passe par une fonction de rappel, qui peut ensuite intercepter les coups de clé: dans ce cas, c'est bricoler avec eux pour le plaisir, changer le curseur gauche à droite, etc. Une application simple appelle alors la DLL et rapporte ses résultats en fonction d'un événement TTimer. Si vous êtes intéressé, je peux poster le code basé sur Delphi 2007.
Il est bien documenté et commenté et vous pourriez potentiellement l'utiliser comme base pour déterminer où une touche va. Si vous pouviez obtenir le handle de l'application qui a envoyé les coups de clé, vous pourriez le suivre de cette façon. Avec cette poignée vous seriez en mesure d'obtenir les informations dont vous avez besoin tout à fait facilement.
D'autres applications ont essayé de déterminer les raccourcis clavier en passant par leurs raccourcis car ils peuvent contenir une touche de raccourci, qui est juste un autre terme pour raccourci clavier. Cependant, la plupart des applications n'ont pas tendance à définir cette propriété, donc elle pourrait ne pas retourner beaucoup. Si vous êtes intéressé par cette route, Delphi a accès à l'interface COM IShellLink
que vous pouvez utiliser pour charger un raccourci et obtenir son raccourci:
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;
Si vous avez accès à Safari Livres en Ligne, il existe un bonne section sur le travail avec des raccourcis / liens shell dans le Borland Delphi 6 Developer's Guide Par Steve Teixeira et Xavier Pacheco. Mon exemple ci-dessus est une version massacrée à partir de là et ce site.
Espérons que cela aide!
Une façon est d'utiliser l'Visual Studio outil Espion++.
Essayez ceci:
- Exécutez l'outil (pour moi, c'est à
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe
) - dans la barre de menus, sélectionnez Spy -> journal des messages... (ou appuyer sur Ctrl + M)
- Vérifier , Toutes les Fenêtres du Système dans le Fenêtres Supplémentaires frame
- passez à l'onglet Messages
- cliquez sur Tout effacer bouton
- sélectionnez
WM_HOTKEY
dans la zone de liste, ou cochez clavier dans groupes de messages (Si vous êtes OK avec plus de bruit potentiel) - cliquez sur le boutonOK
- Appuyez sur la touche en question (Gagner + R, par exemple)
- sélectionnez la ligne
WM_HOTKEY
dans la fenêtreMessages (toutes les fenêtres) , faites un clic droit et sélectionnez propriétés... dans le menu contextuel - dans la boîte de dialoguePropriétés du Message , cliquez sur le lienhandle de fenêtre (ce sera le handle de la fenêtre qui a reçu le message)
- cliquez sur le bouton synchroniser dans la boîte de dialoguePropriétés de la fenêtre . Cela montrera la fenêtre dans la fenêtre principale de Spy++ treeview.
- Sur Propriétés de la Fenêtre boîte de dialogue, sélectionnez Processus onglet
- cliquez sur le lienID de processus . Cela va vous montrer le processus (Dans mon Gagner + R cas:
EXPLORER
)
Après quelques recherches, il semble que vous deviez accéder à la structure interne que MS utilise pour stocker les raccourcis clavier. ReactOS a une implémentation de salle blanche qui implémente l'appel GetHotKey
en itérant une liste interne et en extrayant la touche de raccourci qui correspond aux paramètres de l'appel.
Selon la proximité de L'implémentation de ReactOS avec L'implémentation MS, vous pourrez peut-être fouiller dans la mémoire pour trouver la structure, mais c'est au-dessus de ma tête...
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;
}
Je presume ce fil sur sysinternals a été demandé par quelqu'un lié à cette question, mais je pensais que je ferais un lien de toute façon pour garder les deux ensemble. Le fil semble très intrigant, mais je soupçonne qu'une spéléologie de plongée profonde devrait arriver à comprendre cela sans accès aux internes MS.
En haut de ma tête, vous pouvez essayer d'énumérer toutes les fenêtres avec EnumWindows, puis dans le rappel, envoyez WM_GETHOTKEY à chaque fenêtre.
Edit: apparemment, j'avais tort à ce sujet. MSDN a plus d'informations:
WM_HOTKEY n'est pas lié aux touches de raccourci WM_GETHOTKEY et wm_sethotkey. Le message WM_HOTKEY est envoyé pour les touches de raccourci génériques tandis que les messages wm_sethotkey et wm_gethotkey se rapportent aux touches de raccourci d'activation de fenêtre.
Note: Ici est un programme visant à la fonctionnalité que vous recherchez. Vous pouvez essayer de décompiler il.
Cela semble vous en dire beaucoup: http://hkcmdr.anymania.com/help.html
Un autre thread mentionne un crochet de clavier de niveau NT global:
Réattribuer / remplacer la touche de raccourci (Win + L) pour verrouiller windows
Peut-être que vous pouvez obtenir le handle du processus qui a appelé le crochet de cette façon, vous pouvez ensuite résoudre le nom du processus
(avertissement: je l'avais dans mes signets, Je n'ai pas vraiment essayé / testé)
Je sais que vous pouvez intercepter le flux de messages dans n'importe quelle fenêtre de votre propre processus - ce que nous appelions sous-classement dans VB6. (Bien que je ne me souviens pas de la fonction, peut-être SetWindowLong? Je suis pas sûr si vous pouvez le faire pour windows en dehors de votre propre processus. Mais pour le bien de ce poste permet de supposer que vous trouvez un moyen de le faire. Ensuite, vous pouvez simplement intercepter les messages pour toutes les fenêtres de niveau supérieur, surveiller le message WM_HOTKEY. Vous ne seriez pas en mesure de connaître toutes les clés droite au large de la chauve-souris, mais comme ils ont été pressés, vous pouvez facilement comprendre quelle application les utilisait. Si vous persistez vos résultats sur le disque et que vous les rechargez chaque fois que votre application monitor est exécutée, vous pouvez augmenter les performances de votre application au fil du temps.
Cela ne répond pas exactement à la partie de la question qui concerne L'API Windows, mais il répond à la partie de la question qui concerne une liste de raccourcis clavier globaux et les applications qui les "possèdent".
L'Explorateur de raccourcis clavier gratuit à http://hkcmdr.anymania.com / affiche une liste de tous les raccourcis clavier globaux et des applications qui les possèdent. Cela m'a juste aidé à comprendre pourquoi une touche de raccourci spécifique à l'application a cessé de fonctionner et comment la réparer (en reconfigurant le raccourci clavier global enregistré dans l'application qui l'avait enregistré), en quelques secondes.
Je n'ai pas été un utilisateur Windows hard-core pendant quelques années (je suis passé à Mac). Mais j'avais l'habitude de jurer par Process Explorer pour savoir quel processus utilise un fichier particulier que j'essayais de supprimer. Peut-être que cela aide à savoir quel processus utilise une touche de raccourci?