找出注册全球热键的流程?(Windows API)

Mar*_*ski 105 delphi api winapi hotkeys registerhotkey

据我所知,Windows没有提供API函数来告诉应用程序注册了一个全局热键(通过RegisterHotkey).我只能发现如果RegisterHotkey返回false,则注册了热键,但不是"拥有"热键的人.

在没有直接API的情况下,是否会有迂回的方式?Windows维护与每个注册热键相关联的句柄 - 这有点令人抓狂,因此无法获取此信息.

可能不起作用的示例:发送(模拟)已注册的热键,然后拦截Windows将发送给注册它的进程的热键消息.首先,我不认为拦截消息会显示目标窗口句柄.其次,即使有可能,这也是一件坏事,因为发送热键会触发各种程序中各种可能不需要的活动.

这并不重要,但我已经看到了对这种功能的频繁请求,并且我自己也是注册热键的应用程序的受害者,甚至没有在UI或文档中的任何地方公开它.

(在Delphi工作,只不过是WinAPI的学徒,请善待.)

小智 40

一种可能的方法是使用Visual Studio工具Spy ++.

尝试一下:

  1. 运行该工具(对我来说,它是在C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. 在菜单栏中,选择Spy - > Log messages ...(或点击Ctrl+ M)
  3. 附加Windows框架中检查系统中的所有Windows
  4. 切换到" 消息"选项卡
  5. 单击全部清除按钮
  6. 选择WM_HOTKEY在列表框中,或检查键盘消息组(如果你有更多潜在的噪声OK)
  7. 单击" 确定"按钮
  8. 按下有问题的热键(例如Win+ R)
  9. WM_HOTKEY在" 消息(所有Windows)"窗口中选择该行,右键单击,然后在上下文菜单中选择" 属性... "
  10. 在" 消息属性"对话框中,单击" 窗口句柄"链接(这将是接收消息的窗口的句柄)
  11. 单击" 窗口属性"对话框上的" 同步"按钮.这将在主Spy ++窗口树视图中显示该窗口.
  12. 在" 窗口属性"对话框中,选择" 处理"选项卡
  13. 单击" 进程ID"链接.这将显示你的过程(在我的Win+ R案例:EXPLORER)

  • 在第 8 步中,它不要求热键,按下任何热键后消息窗口都会保持空白。使用来自 https://github.com/westoncampbell/SpyPlusPlus(在 Windows 10 中)的 32 位和 64 位版本。 (5认同)
  • 很棒的答案!只是注意到,64位版本的Spy ++仅捕获64位应用程序的消息**,所以如果在按下热键后_Message log_中没有看到"WM_HOTKEY"消息,则可能需要运行32位版本的Spy ++. (3认同)

Pau*_*auk 19

你的问题引起了我的兴趣,所以我做了一些挖掘,但不幸的是,我没有给你一个正确的答案,我想我会分享我所拥有的.

我在1998年创建了这个创建键盘钩子(在Delphi中)的例子,但在Delphi 2007中可以通过几个调整进行编译.

它是一个带有调用的DLL,它SetWindowsHookEx通过一个回调函数,然后可以拦截键击:在这种情况下,它为了好玩而修改它们,将左光标向右移动等等.一个简单的应用程序然后调用DLL并报告回来其结果基于TTimer事件.如果您有兴趣,我可以发布基于Delphi 2007的代码.

它有很好的文档和评论,你可能会用它作为按键按键的基础.如果您可以获得发送键击的应用程序的句柄,您可以通过这种方式跟踪它.有了这个句柄,您就可以轻松获得所需的信息.

其他应用程序尝试通过快捷方式确定热键,因为它们可以包含快捷键,这只是热键的另一个术语.但是,大多数应用程序不倾向于设置此属性,因此它可能不会返回太多.如果您对该路线感兴趣,Delphi可以访问IShellLinkCOM接口,您可以使用该接口加载快捷方式并获取其热键:

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;
Run Code Online (Sandbox Code Playgroud)

如果您可以访问Safari Books Online,那么Steve Teixeira和Xavier Pacheco在Borland Delphi 6开发人员指南中有一个关于使用快捷方式/ shell链接好部分.我上面的例子是来自那里和这个网站的屠宰版本.

希望有所帮助!


Joh*_*don 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;
}
Run Code Online (Sandbox Code Playgroud)

我认为sysinternals上的这个帖子是由与这个问题相关的人问的,但是我想我还是会链接到它以保持两者在一起.该线程看起来非常有趣,但我怀疑在没有访问MS内部的情况下,需要进行一些深潜探测.