2009-02-08 10 views
5

Sto provando a scrivere un'applicazione che risponde ogni volta che viene premuto il tasto Maiusc, indipendentemente dall'applicazione che ha attualmente l'attenzione.Rispondere alla tastiera quando non è a fuoco? (C#, Vista)

Ho provato questo con SetWindowsHookEx() e con GetKeyboardState(), ma entrambi funzionano solo quando è attiva la finestra dell'applicazione. Ho bisogno che funzioni a livello globale.

Come posso fare?

risposta

5

Nessuna delle risposte fornite mi ha aiutato a risolvere il mio problema, ma ho trovato la risposta da solo. Ecco qui.

Utilizzare SetWindowsHookEx() con WH_KEYBOARD_LL era l'approccio corretto. Tuttavia, gli altri parametri SetWindowsHookEx() sono poco intuitivo:

  • L'ultimo parametro, dwThreadId, deve essere 0.
  • Il secondo-ultimo parametro, hMod, ha bisogno di puntare a qualche DLL. Ho usato User32, che è una DLL che viene sempre caricata comunque ed è utilizzata da tutti i processi con una GUI. Ho avuto questa idea da a CodeProject post about this.

Così, il codice è un po 'come questo:

instance = LoadLibrary("User32"); 
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookFunction, instance, 0); 

La documentazione non è chiara circa la penultima parametro. Dice:

Il parametro hMod deve essere impostato su NULL [...] se la procedura di hook si trova all'interno del codice associato al processo corrente.

Esso non indica che questo vale solo per alcuni tipi di ganci, ma non WH_KEYBOARD_LL e WH_MOUSE_LL.

+0

Sì, è quello che intendono dire: per un mouse di livello basso o un hook per tastiera (o qualsiasi altro hook locale) hMod dovrebbe essere IntPtr.Zero. –

+0

Hmmm, dici che gli altri post non sono stati utili, quindi procedi a pubblicare la stessa risposta che nobugz ha già fornito e contrassegna la tua come risposta corretta. –

+0

Nobugz non dice affatto cosa fare su hMod, e contrariamente al tuo primo commento, questa risposta suggerisce che hMod sia impostato su qualcosa ** altro ** rispetto a IntPtr.Zero. –

5

Dovrete usare SetWindowsHookEx(). Esistono solo due tipi di hook che è possibile implementare in un linguaggio gestito, WH_KEYBOARD_LL e WH_MOUSE_LL. Tutti gli altri hook richiedono una DLL che può essere iniettata in un altro processo. Le DLL gestite non possono essere iniettate, il CLR non può essere inizializzato.

Questo blog post ha un esempio funzionale.

+0

La maggior parte degli altri hook può essere implementata in un linguaggio gestito, ma solo se sono limitati ai thread del processo corrente. I ganci di mouse e tastiera di basso livello sono gli unici hook 'globali' consentiti. –

+0

Questo sfiora la superficie del problema e non raggiunge alcun livello di profondità. –

+1

Questa è una risposta molto specifica alla domanda specifica. È un po 'breve e nasconde alcune informazioni per semplicità, ma contiene tutte le informazioni che uno sviluppatore di software competente avrebbe bisogno. –

2

Se si utilizza la tecnica nel post di riferimento di nobugz, è necessario assicurarsi che il delegato non ottenga i dati raccolti, ad es. usando GC.KeepAlive (_proc) quando si imposta il gancio, altrimenti dopo un periodo indeterminato il gancio smetterà di funzionare quando il Delagate riceve GCed.