Cari tahu proses apa yang mendaftarkan hotkey global? (Windows API)

114

Sejauh yang saya ketahui, Windows tidak menawarkan fungsi API untuk memberi tahu aplikasi apa yang telah mendaftarkan hotkey global (melalui RegisterHotkey). Saya hanya dapat mengetahui bahwa hotkey terdaftar jika RegisterHotkey mengembalikan false, tetapi bukan siapa yang "memiliki" hotkey tersebut.

Jika tidak ada API langsung, mungkinkah ada jalan memutar? Windows mempertahankan pegangan yang terkait dengan setiap hotkey yang terdaftar - agak menjengkelkan bahwa seharusnya tidak ada cara untuk mendapatkan informasi ini.

Contoh sesuatu yang mungkin tidak akan berfungsi: kirim (simulasikan) hotkey terdaftar, lalu intersep pesan hotkey yang akan dikirim Windows ke proses yang mendaftarkannya. Pertama, saya tidak berpikir mencegat pesan akan mengungkapkan pegangan jendela tujuan. Kedua, bahkan jika memungkinkan, itu akan menjadi hal yang buruk untuk dilakukan, karena mengirim hotkeys akan memicu segala macam aktivitas yang mungkin tidak diinginkan dari berbagai program.

Tidak ada yang penting, tetapi saya sering melihat permintaan untuk fungsionalitas seperti itu, dan saya sendiri telah menjadi korban dari aplikasi yang mendaftarkan hotkey tanpa mengungkapkannya di mana pun di UI atau dokumen.

(Bekerja di Delphi, dan tidak lebih dari magang di WinAPI, mohon berbaik hati.)

Marek Jedliński
sumber

Jawaban:

20

Pertanyaan Anda menarik minat saya, jadi saya telah melakukan sedikit penggalian dan sementara, sayangnya saya tidak memiliki jawaban yang tepat untuk Anda, saya pikir saya akan membagikan apa yang saya miliki.

Saya menemukan contoh pembuatan hook keyboard ini (dalam Delphi) yang ditulis pada tahun 1998, tetapi dapat dikompilasi di Delphi 2007 dengan beberapa tweak.

Ini adalah DLL dengan panggilan ke SetWindowsHookExyang melewati fungsi panggilan balik, yang kemudian dapat menghalangi penekanan tombol: Dalam hal ini, ia mengotak-atiknya untuk bersenang-senang, mengubah kursor kiri ke kanan, dll. Sebuah aplikasi sederhana kemudian memanggil DLL dan melaporkan kembali hasilnya berdasarkan acara TTimer. Jika Anda tertarik, saya dapat memposting kode berbasis Delphi 2007.

Ini didokumentasikan dan dikomentari dengan baik dan Anda berpotensi dapat menggunakannya sebagai dasar untuk menentukan ke mana penekanan tombol akan dilakukan. Jika Anda bisa mendapatkan pegangan aplikasi yang mengirim penekanan tombol, Anda dapat melacaknya kembali seperti itu. Dengan pegangan itu Anda akan bisa mendapatkan informasi yang Anda butuhkan dengan cukup mudah.

Aplikasi lain telah mencoba menentukan tombol pintas dengan menelusuri Pintasannya karena dapat berisi tombol Pintasan, yang merupakan istilah lain untuk tombol pintas. Namun sebagian besar aplikasi tidak cenderung menyetel properti ini sehingga mungkin tidak mengembalikan banyak. Jika Anda tertarik dengan rute itu, Delphi memiliki akses ke IShellLinkantarmuka COM yang dapat Anda gunakan untuk memuat pintasan dan mendapatkan hotkey-nya:

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;

Jika Anda memiliki akses ke Buku Safari Online , ada bagian bagus tentang bekerja dengan pintasan / tautan shell di Panduan Pengembang Borland Delphi 6 oleh Steve Teixeira dan Xavier Pacheco. Contoh saya di atas adalah versi yang dibantai dari sana dan situs ini .

Semoga membantu!

Pauk
sumber
59

Salah satu cara yang mungkin adalah dengan menggunakan alat Visual Studio Spy ++ .

Cobalah ini:

  1. Jalankan alatnya (bagi saya, ada di C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\spyxx_amd64.exe)
  2. Di bilah menu, pilih Spy -> Log messages ... (atau tekan Ctrl+ M)
  3. Periksa Semua Windows di Sistem dalam bingkai Windows Tambahan
  4. Beralih ke tab Pesan
  5. Klik Batal Semua tombol
  6. Pilih WM_HOTKEYdi kotak daftar, atau centang Keyboard di Grup Pesan (jika Anda setuju dengan potensi gangguan yang lebih banyak)
  7. Klik tombol OK
  8. Tekan tombol pintas yang dimaksud ( Win+ R, misalnya)
  9. Pilih WM_HOTKEYbaris di jendela Pesan (Semua Windows) , klik kanan, dan pilih Properti ... di menu konteks
  10. Dalam dialog Properti Pesan , klik tautan Tangani Jendela (ini akan menjadi pegangan untuk jendela yang menerima pesan)
  11. Klik tombol Sinkronisasi pada dialog Properti Jendela . Ini akan menampilkan jendela di tampilan pohon jendela Spy ++ utama.
  12. Pada dialog Properti Jendela , pilih tab Proses
  13. Klik tautan ID Proses . Ini akan menunjukkan proses (Dalam saya Win+ Rkasus: EXPLORER)
pengguna995048
sumber
6
Jawaban yang bagus! Sebagai catatan , Spy ++ versi 64-bit hanya menangkap pesan untuk aplikasi 64-bit , jadi jika Anda tidak melihat WM_HOTKEYpesan di log Pesan setelah menekan tombol pintas, Anda mungkin perlu menjalankan Spy ++ versi 32-bit .
David Ferenczy Rogožan
TERIMA KASIH BANYAK!!! Saya pada dasarnya menyerah untuk menggunakan beberapa pintasan sampai saya menemukan ini.
thewindev
3
Pada langkah 8 tidak meminta hotkey, jendela pesan tetap kosong setelah menekan hotkey apa pun. Versi 32 dan 64-bit yang digunakan dari github.com/westoncampbell/SpyPlusPlus (di Windows 10).
CoolMind
9

Setelah beberapa penelitian, tampaknya Anda perlu mendapatkan akses ke struktur internal yang digunakan MS untuk menyimpan hotkey. ReactOS memiliki implementasi ruang bersih yang mengimplementasikan GetHotKeypanggilan dengan mengulang daftar internal dan mengekstrak hotkey yang cocok dengan parameter panggilan.

Bergantung pada seberapa dekat implementasi ReactOS dengan implementasi MS, Anda mungkin dapat melihat-lihat dalam memori untuk menemukan strukturnya, tapi itu di luar kepala saya ...

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;
}

Saya kira utas tentang sysinternals ini ditanyakan oleh seseorang yang terkait dengan pertanyaan ini, tetapi saya pikir saya akan menautkannya untuk menjaga keduanya tetap bersama. Utasnya terlihat sangat menarik, tetapi saya menduga bahwa beberapa spelunking yang mendalam perlu terjadi untuk mengetahui hal ini tanpa akses ke internal MS.

John Weldon
sumber
3

Di luar kepalaku, Anda dapat mencoba menghitung semua jendela dengan EnumWindows, lalu di callback, kirim WM_GETHOTKEY ke setiap jendela.

Edit: Sepertinya saya salah tentang itu. MSDN memiliki lebih banyak informasi:

WM_HOTKEY tidak terkait dengan tombol pintas WM_GETHOTKEY dan WM_SETHOTKEY. Pesan WM_HOTKEY dikirim untuk kunci pintas generik sedangkan pesan WM_SETHOTKEY dan WM_GETHOTKEY terkait dengan kunci pintas aktivasi jendela.

Catatan: Berikut adalah program yang mengaku memiliki fungsionalitas yang Anda cari. Anda dapat mencoba membongkar itu.

David
sumber
3
Tautan ke program sekarang benar-benar rusak. Program apa itu? Sering kali saya ingin mencari tahu program mana yang mendaftarkan hotkey saya karena tiba-tiba mereka tidak berfungsi lagi atau melakukan hal-hal baru yang mengganggu.
James Oltmans
(Seringkali, Wayback Machine dapat membantu jika halaman web hilang, tetapi di sini juga hanya mencerminkan 404 Not Found: http://web.archive.org/web/*/tds.diamondcs.com.au/dse/ deteksi / hotkeys.php )
Aaron Thoma
2

Ini sepertinya memberi tahu Anda banyak hal: http://hkcmdr.anymania.com/help.html

Caveatrob
sumber
1
Melakukannya? DLL yang menyamar sebagai pengemudi? Fungsi DLL diekspor sebagai hookegunaan SetWindowHookExuntuk mengatur dua kait, satu WH_KEYBOARD_LLdan satu WH_GETMESSAGE... sisanya harus cukup banyak didokumentasikan di MSDN.
0xC0000022L
Jangan gunakan aplikasi ini di Windows 8 atau 10.
Jeff Lange
1

Utas lain menyebutkan pengait keyboard tingkat NT global:

Tetapkan ulang / timpa hotkey (Win + L) untuk mengunci jendela

mungkin Anda bisa mendapatkan pegangan dari proses yang disebut hook seperti itu, yang kemudian bisa Anda selesaikan ke nama proses

(penafian: Saya memilikinya di bookmark saya, belum benar-benar mencoba / menguji)

Marco van de Voort
sumber
0

Saya tahu Anda dapat mencegat aliran pesan di jendela mana pun dalam proses Anda sendiri - apa yang biasa kami sebut subclassing di VB6. (Meskipun saya tidak ingat fungsinya, mungkin SetWindowLong?) Saya tidak yakin apakah Anda dapat melakukan ini untuk windows di luar proses Anda sendiri. Tetapi demi posting ini mari kita asumsikan Anda menemukan cara untuk melakukan itu. Kemudian Anda cukup mencegat pesan untuk semua jendela tingkat atas, memantau pesan WM_HOTKEY. Anda tidak akan bisa langsung mengetahui semua tombol, tapi saat ditekan, Anda bisa dengan mudah mengetahui aplikasi apa yang menggunakannya. Jika Anda mempertahankan hasil Anda ke disk dan memuat ulang setiap kali aplikasi monitor Anda dijalankan, Anda dapat meningkatkan kinerja aplikasi Anda dari waktu ke waktu.

Sam Axe
sumber
-1

Ini tidak benar-benar menjawab bagian dari pertanyaan tentang Windows API, tetapi menjawab bagian dari pertanyaan tentang daftar hotkey global dan aplikasi yang "memiliki" mereka.

Hotkey Explorer gratis di http://hkcmdr.anymania.com/ menampilkan daftar semua hotkey global dan aplikasi yang memilikinya. Ini hanya membantu saya mencari tahu mengapa tombol pintas khusus aplikasi berhenti berfungsi dan cara memperbaikinya (dengan mengkonfigurasi ulang tombol pintas global terdaftar di aplikasi yang telah mendaftarkannya), dalam beberapa detik.

Gerhard
sumber
4
menginstalnya dan berfungsi seperti virus, setidaknya program dengan tujuan mal, seperti lelucon yang buruk. Membuka semua jenis jendela, mengaktifkan narator suara, dll.
Flion
3
@Flion: Lihat diskusi di superuser.com/a/191090/3617 . Pada dasarnya, beberapa penggunaan hotkey bekerja dengan memeriksa setiap kombinasi tombol yang memungkinkan. Pada Windows 8+, (dan pada tingkat yang lebih rendah pada Windows 7), teknik probing ini memicu setiap kombinasi tombol, bukan hanya menanyakannya.
Brian
@Flion FWIW, saya menggunakannya di Win7 dengan sukses. Tetapi jika saya memahami Brian dengan benar, ini mungkin tidak berfungsi dengan baik dengan versi yang lebih baru, dan seberapa baik kerjanya mungkin juga bergantung pada tombol pintas khusus yang ditentukan.
Gerhard