找出注册了全局热键的进程? (WindowsAPI)

据我所知,Windows 没有提供一个 API 函数来告诉哪个应用程序已经注册了一个全局热键(通过 RegisterHotkey)。我只能发现一个热键注册如果 RegisterHotkey 返回 false,但没有谁“拥有”热键。

在没有直接 API 的情况下,是否有一种迂回的方法?Windows 维护与每个注册热键相关联的句柄——这有点令人恼火,因为没有办法获得这些信息。

例如: 发送(模拟)一个已注册的热键,然后拦截 Windows 将发送到注册它的进程的热键消息。首先,我不认为拦截消息会暴露目的地窗口句柄。其次,即使这是可能的,这将是一件坏事做,因为发送热键将触发各种潜在的不必要的活动从各种程序。

这并不重要,但是我经常看到对这种功能的请求,而且我自己也是那些注册热键却不在 UI 或文档中任何地方公开的应用程序的受害者。

(在 Delphi 工作,不过是 WinAPI 的学徒,请友好一点。)

38345 次浏览

另一个帖子提到了一个全球 NT 级别的键盘挂钩:

重新分配/覆盖热键(Win + L)来锁定窗口

也许您可以通过这种方式获得调用钩子的进程的句柄,然后可以将其解析为进程名

(免责声明: 我把它放在书签里了,还没有真正尝试/测试过)

我知道您可以在您自己的进程中的任何窗口中拦截消息流——在 VB6中我们过去称之为子类化。(虽然我不记得这个函数了,也许是 SetWindowLong?)我不确定您是否可以在自己的流程之外对窗口进行此操作。但是为了这篇文章,让我们假设你找到了一个方法来做到这一点。然后您可以简单地拦截所有顶级窗口的消息,监视 WM _ HOTKEY 消息。您不可能一下子就知道所有的键,但是当它们被按下时,您可以很容易地找出使用它们的应用程序。如果在每次运行监视器应用程序时都将结果保存到磁盘并重新加载,则可以随着时间的推移提高应用程序的性能。

经过一些研究,似乎你需要访问 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;
}

我猜想 这个关于系统内部的线程是由与这个问题相关的人提出的,但是我想我还是会链接到它,以便将两者结合起来。这个主线看起来非常有趣,但是我怀疑一些深入的洞穴探险需要发生在没有进入 MS 内部的情况下才能解决这个问题。

您可以尝试使用 EnumWindows 枚举所有窗口,然后在回调中向每个窗口发送 WM _ GETHOTKEY。

编辑: 显然我错了。 MSDN有更多信息:

WM _ HOTKEY 与 WM _ GETHOTKEY 和 WM _ SETHOTKEY 热键无关。WM _ HOTKEY 消息用于一般热键,而 WM _ SETHOTKEY 和 WM _ GETHOTKEY 消息用于窗口激活热键。

注意: 给你是一个声称具有您正在寻找的功能的程序。您可以尝试反编译它。

你的问题引起了我的兴趣,所以我做了一些调查,虽然,不幸的是,我没有一个适当的答案给你,我想我会分享我有什么。

我发现这个 创建键盘挂钩的示例(在 Delphi 中)编写于1998年,但是在 Delphi 2007中可以编译,只需要做一些调整。

它是一个 DLL,通过一个回调函数调用 SetWindowsHookEx,该函数可以拦截按键: 在这种情况下,它是为了好玩而对按键进行修补,将左光标更改为右光标,等等。然后,一个简单的应用程序调用 DLL 并基于 TTimer 事件报告其结果。如果你感兴趣,我可以发布基于 Delphi 2007的代码。

这是很好的文件和评论,你可以使用它作为一个基础,工作了一个关键新闻是去哪里。如果您能够获得发送按键的应用程序的句柄,就可以通过这种方式对其进行跟踪。有了这个把手,你就可以很容易地得到你需要的信息。

其他应用程序已经尝试通过他们的快捷键来确定热键,因为他们可以包含一个快捷键,这只是热键的另一个术语。然而,大多数应用程序不会设置此属性,因此它可能不会返回太多内容。如果你对这条路线感兴趣,Delphi 可以访问 IShellLink COM 接口,你可以用它来加载快捷方式并获得热键:

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;

如果你已经访问了 Safari 图书在线,有一个 有关使用快捷方式/shell 链接的部分在 Borland Delphi 6开发者指南由史蒂夫 Teixeira 和 Xavier Pacheco。我上面的例子是一个屠宰版本从那里和 这个网站

希望能帮上忙!

这并没有完全回答关于 Windows API 的那部分问题,但它回答了关于全局热键列表和“拥有”它们的应用程序的那部分问题。

http://hkcmdr.anymania.com/的免费热键浏览器显示了所有全局热键和拥有它们的应用程序的列表。这只是帮助我弄清楚为什么一个应用程序特定的快捷键停止工作,以及如何修复它(通过重新配置已注册的应用程序中的注册全局热键) ,在几秒钟之内。

一种可能的方法是使用 < strong > Visual Studio tool Spy + +

试试这个:

  1. 运行工具(对我来说,它是在 C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe或者你可以 下载)
  2. 在菜单栏中,选择 间谍-> 记录信息。(或者按 Ctrl + M)
  3. 检查 附加窗口帧中的 系统中的所有窗口
  4. 切换到 信息选项卡
  5. 单击 安全按钮
  6. 在列表框中选择 WM_HOTKEY,或者在 消息群组中选择 键盘(如果可以选择更多的潜在噪音)
  7. 单击 好的按钮
  8. 按有问题的热键(例如,Win + R)
  9. 消息(所有窗口)窗口中选择 WM_HOTKEY行,右键单击,然后在上下文菜单中选择 地产..。
  10. 消息属性对话框中,单击 窗把手链接(这将是接收消息的窗口的句柄)
  11. 单击 窗口属性对话框上的 同步按钮。这将显示主 Spy + + 窗口树视图中的窗口(如果是窗口本身或某个弹出式应用程序,则不显示任何内容)。
  12. 窗口属性对话框中,选择 过程选项卡
  13. 单击 进程 ID链接。这将向您显示过程(在我的 Win + R案例中: EXPLORER)