2011-12-27 16 views
10

Qual è il modo più veloce per determinare la pressione di un tasto e anche come determinare se un tasto è in attesa? Sembra che la messaggistica delle finestre sia lenta. Fornisci un esempio di come farlo e perché è più veloce di un'alternativa.Qual è il modo più veloce per determinare la pressione di un tasto e il mantenimento della chiave in Win32?

Per essere chiari, questo per un loop di tempo reale (una simulazione), quindi sto cercando il modo più veloce per determinare se un tasto è stato premuto e anche per verificare se è tenuto.

+0

"Sembra che la messaggistica delle finestre sia lenta." Veramente? Questo è difficile da determinare poiché è impossibile per il programma calcolare il ritardo tra il momento in cui l'utente ha premuto il tasto e il momento in cui è stato elaborato il messaggio della finestra. È per sentito dire che in qualche modo l'hai misurato per essere troppo lento? –

+0

L'ho misurato in loop in tempo reale, in genere occorrono alcune zecche per dare il via. E l'ho anche sentito molte volte negli ultimi anni. – judeclarke

+0

@judeclarke: Quanto dura un "tick"? E come definisci "lento"? –

risposta

21

GetAsyncKeyState() è quello che stai cercando. Legge lo stato fisico della tastiera, indipendentemente dallo stato della coda di input. Se è impostato il bit più alto, il tasto è stato disattivato al momento della chiamata.

// Fetch tab key state. 
SHORT tabKeyState = GetAsyncKeyState(VK_TAB); 

// Test high bit - if set, key was down when GetAsyncKeyState was called. 
if((1 << 15) & tabKeyState) 
{ 
    // TAB key down... 
} 

Inoltre, per la cronologia, Windows non è un sistema operativo in tempo reale. Se la tua applicazione richiede precisione in tempo reale, potresti voler selezionare un'altra piattaforma.

+0

Può per favore fornire un esempio del suo utilizzo? – judeclarke

+0

Aggiornato con il campione, come richiesto. – Bukes

+0

Dopo aver fatto numerosi test, sembra che questo sia esattamente quello che stavo cercando. Questo è decisamente più reattivo di una semplice messaggistica di Windows. Grazie per l'aiuto. – judeclarke

2

Considerando che tutte le comunicazioni inter-windows sono tramite Windows Messaging (eventi di tastiera, eventi del mouse, praticamente tutti gli eventi che si possono immaginare), non esiste un modo inferiore per accedere agli eventi della tastiera (a meno che non si scriva il proprio driver della tastiera) che conosco.

DirectX utilizza ancora la messaggistica da tastiera di Windows per fornire ai programmatori DirectX un accesso più semplice agli eventi della tastiera.

Aggiornato

mia nota su DirectX non era quello di usarlo, ma che quando Microsoft ha voluto fare un'interfaccia per i programmatori di utilizzare per i giochi in tempo reale, che ancora scritto DirectX in cima al di Windows Message Queue .

Suggerirei di dare un'occhiata a come scrivere un programma che può leggere direttamente dalla coda dei messaggi. Credo che ci sia un buon esempio Code Project Windows Message Handling - Part 1.

Le tue due opzioni sono leggere dalla coda messaggi (memorizzate nel buffer) o leggere direttamente dallo stato della tastiera (come afferma Bukes), il che significa che il tuo loop potrebbe tecnicamente perdere un evento della tastiera per un numero qualsiasi di motivi.

+0

Se per DirectX si intende DirectInput, è stato deprecato. Se per DirectX intendi XInput, ci sono state numerose fonti che dicono di utilizzare l'input non elaborato su XInput \ DirectInput. Esistono alternative a questi e messaggi, come GetKeyState e GetKeyboardState, tuttavia, non sono sicuro che quelle siano la soluzione migliore. – judeclarke

+0

Aggiornato per il tuo commento. –

6

Se si desidera solo per interrogare lo stato della tastiera in modo da scoprire quali tasti sono su/giù così come il spostamento/alt/ctrl stato, basta chiamare GetKeyboardState (MSDN reference).

Quando ho lavorato in uno studio di gioco, questo è esattamente il modo in cui abbiamo ottenuto lo stato della tastiera per ciascun fotogramma. Dovrebbe essere applicabile al tuo codice di simulazione.

+0

Update. Probabilmente andrò a svendere la mia risposta a favore della risposta di @Bukes qui sotto. Secondo MSDN per GetKeyboardState: un'applicazione può chiamare questa funzione per recuperare lo stato corrente di tutte le chiavi virtuali. Lo stato cambia come un thread rimuove i messaggi della tastiera dalla coda dei messaggi. Lo stato non cambia quando i messaggi della tastiera vengono registrati o recuperati dalle code di messaggi di altri thread. – selbie

+0

Tenendo presente quanto sopra, se si stanno pompando messaggi (GetMessage e DispatchMessage su ciascun fotogramma della simulazione, è possibile utilizzare OK GetKeyboardState. Altrimenti, GetAsyncKeyState. – selbie

+0

Grazie per l'aiuto, stavo pompando messaggi su ciascun fotogramma Ho finito per scegliere Bukes, ma tu sei stato sicuramente d'aiuto (quindi ho fatto un upvoted, dato che anche il tuo è probabilmente uno scenerio probabilmente per qualcun altro) – judeclarke

2

TL; DR: è possibile utilizzare GetAsyncKeyState per verificare se una chiave è attualmente verso il basso, ma per la migliore risposta delle applicazioni alla pressione dei tasti e rilascia, si desidera utilizzare il codice di condotta Win32 vicino al fondo del mio post.

GetAsyncKeyState opere perfettamente bene per determinare se una chiave è attualmente verso il basso, ma in termini di determinare se un tasto è stato premuto o rilasciato e quante volte questo è stato fatto, GetAsyncKeyState perde delle battute in una CPU- applicazione intensiva, anche dopo aver memorizzato lo stato della chiave precedente.

questo era quello che ho provato:

static const unsigned int NumberOfKeys = 256U; 

bool previousKeyboardState[NumberOfKeys]; 

//Get the current state of each key as the application starts to ensure that keys held down beforehand are not processed as pressed keys. 
for (unsigned int keyNum = 0U; keyNum < NumberOfKeys; ++keyNum) 
{ 
    previousKeyboardState[keyNum] = isKeyDown(keyNum); 
} 

//Works fine. 
bool isKeyDown(int key) 
{ 
    return (GetAsyncKeyState(key) & (1 << 16)); 
} 

//Misses key presses when application is bogged down. 
bool isKeyFirstPressed(int key) 
{ 
    bool previousState = previousKeyboardState[key]; 

    previousKeyboardState[key] = isKeyDown(key); 

    return (previousKeyboardState[key] && !previousState); 
} 

//Misses key releases when application is bogged down. 
bool isKeyFirstReleased(int key) 
{ 
    bool previousState = previousKeyboardState[key]; 

    previousKeyboardState[key] = isKeyDown(key); 

    return (!previousKeyboardState[key] && previousState); 
} 


//Example usage: 

if (isKeyDown(VK_W)) 
{ 
    //W key. 
} 

if (isKeyFirstReleased(VK_SNAPSHOT)) 
{ 
    //Print screen. 
} 

GetKeyboardState è non va bene neanche, in quanto non tiene traccia del numero di tasti da premere o rilasci. Come ha detto Erik Philips nella sua risposta, queste sono soluzioni senza buffer, che non vanno bene se si è, ad es. scrivere un gioco. Dovresti elaborare tutte le sequenze di tasti più velocemente di quanto non siano state ricevute.

Ora, il mio codice sopra funziona in modo decente e può essere adatto a molte persone, ma preferisco di gran lunga non perdere un singolo tasto. I odio utilizzando applicazioni che non rispondono. Penso che la soluzione migliore per le applicazioni Win32 sia quella di catturare i messaggi WM_KEYDOWN e WM_KEYUP nella pipeline ed elaborarli. La cosa bella è che WM_KEYDOWN fornisce anche un conteggio a ripetizione automatica, che potrebbe essere utile per le applicazioni che supportano l'immissione di testo (ad es. Chat, IDE, ecc.). Questo aggiunge anche una piccola complicazione, che è menzionato nella documentazione WM_KEYDOWN:

A causa della caratteristica Autorepeat, più di un messaggio WM_KEYDOWN può essere pubblicato prima che un messaggio WM_KEYUP è distaccato. Lo stato del tasto precedente (bit 30) può essere utilizzato per determinare se il messaggio WM_KEYDOWN indica la prima transizione verso il basso o una transizione verso il basso ripetuta.

Ci sono anche ganci per tastiera di Windows che è possibile esaminare, ma sono più difficili da usare. Sono bravi a ricevere key press globali.

+0

Solo dicendo: un 'SHORT' è 16-bit,' (1 << 16) 'cast come' SHORT' è 'zero'. Non intendi' (1 << 15) 'per indicare il bit più alto di un' SHORT'? –

+0

Sei sicuro che un SHORT è 16 bit? – Andrew

+0

definizione A meno che qualcuno faccia qualcosa di sciocco, come 'typedef long SHORT;' –

Problemi correlati