web-dev-qa-db-ja.com

グローバルホットキーを登録したプロセスを確認しますか? (Windows API)

私が知る限り、Windowsは(RegisterHotkeyを介して)グローバルホットキーを登録したアプリケーションを通知するAPI関数を提供していません。 RegisterHotkeyがfalseを返した場合にのみホットキーが登録されますが、ホットキーを「所有」している人はいないことがわかります。

直接APIがない場合、回り道はありますか? Windowsは、登録された各ホットキーに関連付けられたハンドルを保持します。この情報を取得する方法がないはずだというのは少し気が重いです。

動作しない可能性が高い例:登録済みのホットキーを送信(シミュレート)し、Windowsがそれを登録したプロセスに送信するホットキーメッセージをインターセプトします。まず、メッセージを傍受しても宛先ウィンドウハンドルが明らかになるとは思わない。第二に、たとえ可能だったとしても、ホットキーを送信するとさまざまなプログラムから潜在的に不要なあらゆる種類のアクティビティがトリガーされるため、それは悪いことです。

重要なことは何もありませんが、そのような機能に対する頻繁なリクエストを目にし、UIやドキュメントのどこにも公開せずにホットキーを登録するアプリケーションの犠牲になりました。

(Delphiで働いており、WinAPIの見習いにすぎないので、親切にしてください。)

101

あなたの質問が私の興味をそそったので、少し掘り下げましたが、残念ながらあなたに適切な答えがありませんが、私が持っているものを共有すると思いました。

私はこれを見つけました 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 Books Online にアクセスできる場合は、Steve TeixeiraとXavier PachecoによるBorland Delphi 6開発者ガイドに ショートカットの操作に関する良いセクション/シェルリンク があります。 。上記の私の例は、そこから屠殺されたバージョンであり、 このサイト です。

お役に立てば幸いです!

19
Pauk

可能な方法の1つは、 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. 追加ウィンドウフレームのシステム内のすべてのウィンドウをチェックします
  4. Messagesタブに切り替えます
  5. Clear Allボタンをクリックします
  6. 選択する WM_HOTKEYリストボックスで、またはKeyboardMessage Groupsで確認します(ノイズが発生する可能性がある場合は)
  7. [〜#〜] ok [〜#〜]ボタンをクリックします
  8. 問題のホットキーを押します(Win + R、 例えば)
  9. を選択 WM_HOTKEYMessages(All Windows)ウィンドウで右クリックし、コンテキストメニューでProperties ...を選択
  10. Message Propertiesダイアログで、Window Handleリンクをクリックします(これは、メッセージを受信したウィンドウのハンドルになります)
  11. ウィンドウのプロパティダイアログの同期ボタンをクリックします。これにより、メインのSpy ++ウィンドウツリービューにウィンドウが表示されます。
  12. ウィンドウのプロパティダイアログで、プロセスタブを選択します
  13. プロセスIDリンクをクリックします。これにより、プロセスが表示されます( Win + R ケース:Explorer
33
user995048

いくつかの調査の後、ホットキーを保存するために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;
}

sysinternalsのこのスレッド はこの質問に関連する誰かから尋ねられたと思いますが、私は2つを一緒に保つためにとにかくリンクすると思いました。スレッドは非常に興味をそそられるように見えますが、MS内部にアクセスせずにこれを理解するために、深いダイビングスペルクが発生する必要があると思われます。

9
John Weldon

頭の中で、すべてのウィンドウをEnumWindowsで列挙してから、コールバックでWM_GETHOTKEYを各ウィンドウに送信してみてください。

編集:どうやら私はそれについて間違っていた。 [〜#〜] msdn [〜#〜] には詳細情報があります。

WM_HOTKEYは、WM_GETHOTKEYおよびWM_SETHOTKEYホットキーとは無関係です。 WM_HOTKEYメッセージは一般的なホットキーに対して送信され、WM_SETHOTKEYおよびWM_GETHOTKEYメッセージはウィンドウアクティベーションホットキーに関連しています。

注: ここ は、お探しの機能を備えていることを意図したプログラムです。それを逆コンパイルしてみてください。

3
David

これは多くのことを伝えているようです: http://hkcmdr.anymania.com/help.html

2
Caveatrob

別のスレッドは、グローバルなNTレベルのキーボードフックに言及しています。

ウィンドウをロックするためにホットキー(Win + L)を再割り当て/オーバーライド

フックをそのように呼び出したプロセスのハンドルを取得して、プロセス名に解決することができます

(免責事項:ブックマークに入れましたが、実際に試したりテストしたりしていません)

1

独自のプロセス内の任意のウィンドウでメッセージのストリームをインターセプトできることを知っています-これはVB6でサブクラス化と呼ばれていました。 (関数、おそらくSetWindowLongを覚えていませんが?)自分のプロセス外のウィンドウでこれを行うことができるかどうかはわかりません。しかし、この投稿のために、あなたがそれを行う方法を見つけると仮定しましょう。次に、すべてのトップレベルウィンドウのメッセージをインターセプトし、WM_HOTKEYメッセージを監視します。すぐにすべてのキーを知ることはできませんが、キーが押されると、どのアプリケーションがそれらを使用しているかを簡単に把握できます。結果をディスクに保持し、モニターアプリケーションを実行するたびにリロードすると、アプリケーションのパフォーマンスを徐々に向上させることができます。

0
Sam Axe