2009-11-17 15 views
10

[EDIT 3] Ho risolto il problema "utilizzando" la versione "strana". Almeno per le chiavi più importanti. È sufficiente per il mio caso, in cui voglio verificare che ALT e ALT + A non siano uguali (assicurandoti quindi che A non venga premuto). Non perfetto, ma già molto tempo per un problema così piccolo. Grazie per tutte le risposte comunque ... [EDIT 3]Rileva se viene premuto un tasto qualsiasi in C# (non A, B, ma nessuno)

[EDIT 4] risolto molto più pulito grazie alla 280Z28 [/ EDIT 4]

so come verificare la presenza di tasti modificatori e come testare per una singola chiave. Il problema è che voglio controllare se viene premuto un tasto. Il seguente approccio sembra "strano" :-)

WPF applicazione scritta in C#

if (Keyboard.IsKeyDown(Key.A)) return true; 
if (Keyboard.IsKeyDown(Key.B)) return true; 
if (Keyboard.IsKeyDown(Key.C)) return true; 

So che è un enum, così ho pensato di un ciclo, ma qual è il "maggior numero" usare. E questo è possibile? btw, è un caso molto speciale, normalmente userei un evento, ma in questo caso devo farlo in questo modo. Sfortunatamente, non esiste una tastiera "elenco" Keyboard.CurrentlyDown. Almeno non l'ho visto.

Grazie, Chris

EDIT: Ok, perché sembra essere un affare più grande, qui la ragione di questo: Ho definito un "keyset" che funge da DictionaryKey per funzioni personalizzate. Se qualcuno fa clic su un elemento, il wrapper scorre il dizionario e controlla se uno qualsiasi dei "Keyset" predefiniti è attivo.

Ciò consente di definire semplici trigger, come ad es. Esegui questa funzione se ALT + A + B viene premuto. Un'altra opzione è ad es. Esegui questa funzione se ALT + STRG + A viene premuto (durante un clic del mouse su un elemento WPF).

L'unico "problema" con l'implementazione corrente, se definisco un Keyset che NON contiene alcun tasto REAL, come eseguire se ALT viene premuto, viene attivato anche se si preme ALT + A. Oh, mentre scrivo questo, mi rendo conto che c'è un altro problema. Al momento ALT + A + B si attiva anche se si preme ALT + A + B + C.

Forse il mio approccio è sbagliato, e dovrei creare un "rilevatore di tasti statici" e confrontare il keyset con i suoi valori (acquisiti tramite eventi). Farò un tentativo.

EDIT 2 Questo non funziona, almeno non in modo semplice. Ho bisogno di un FrameworkElement da collegare a KeyDown, ma non ce l'ho in un costruttore statico. E io non sono interessato a KeyDownEvents di un certo elemento, ma "globalmente" ... Penso che spingo a rimandare questo problema, non è così importante. Eppure, se qualcuno sa di una migliore approccio diverso ...

Così a lungo, per chi se ne frega, qui qualche codice:

public class KeyModifierSet 
{ 
    internal readonly HashSet<Key> Keys = new HashSet<Key>(); 
    internal readonly HashSet<ModifierKeys> MKeys = new HashSet<ModifierKeys>(); 

    public override int GetHashCode() 
    { 
     int hash = Keys.Count + MKeys.Count; 
     foreach (var t in Keys) 
     { 
      hash *= 17; 
      hash = hash + t.GetHashCode(); 
     } 
     foreach (var t in MKeys) 
     { 
      hash *= 19; 
      hash = hash + t.GetHashCode(); 
     } 
     return hash; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as KeyModifierSet); 
    } 
    public bool Equals(KeyModifierSet other) 
    { 
     // Check for null 
     if (ReferenceEquals(other, null)) 
      return false; 

     // Check for same reference 
     if (ReferenceEquals(this, other)) 
      return true; 

     // Check for same Id and same Values 
     return Keys.SetEquals(other.Keys) && MKeys.SetEquals(other.MKeys); 
    } 

    public bool IsActive() 
    { 
     foreach (var k in Keys) 
      if (Keyboard.IsKeyUp(k)) return false; 

     if ((Keys.Count == 0) && !Keyboard.IsKeyDown(Key.None)) return false; 


     foreach (var k in MKeys) 
      if ((Keyboard.Modifiers & k) == 0) return false; 

     if ((MKeys.Count == 0) && Keyboard.Modifiers > 0) return false; 

     return true; 
    } 


    public KeyModifierSet(ModifierKeys mKey) 
    { 
     MKeys.Add(mKey); 
    } 
    public KeyModifierSet() 
    { 

    } 
    public KeyModifierSet(Key key) 
    { 
     Keys.Add(key); 
    } 
    public KeyModifierSet(Key key, ModifierKeys mKey) 
    { 
     Keys.Add(key); 
     MKeys.Add(mKey); 
    } 
    public KeyModifierSet Add(Key key) 
    { 
     Keys.Add(key); 
     return this; 
    } 
    public KeyModifierSet Add(ModifierKeys key) 
    { 
     MKeys.Add(key); 
     return this; 
    } 
} 
+2

Qual è la vostra applicazione? Console? Windows Forms? WPF? Sito web? – jrista

+0

Vedere titolo ... .NET C# –

+0

Ciò non aiuta. –

risposta

10
[DllImport("user32.dll", EntryPoint = "GetKeyboardState", SetLastError = true)] 
private static extern bool NativeGetKeyboardState([Out] byte[] keyStates); 

private static bool GetKeyboardState(byte[] keyStates) 
{ 
    if (keyStates == null) 
     throw new ArgumentNullException("keyState"); 
    if (keyStates.Length != 256) 
     throw new ArgumentException("The buffer must be 256 bytes long.", "keyState"); 
    return NativeGetKeyboardState(keyStates); 
} 

private static byte[] GetKeyboardState() 
{ 
    byte[] keyStates = new byte[256]; 
    if (!GetKeyboardState(keyStates)) 
     throw new Win32Exception(Marshal.GetLastWin32Error()); 
    return keyStates; 
} 

private static bool AnyKeyPressed() 
{ 
    byte[] keyState = GetKeyboardState(); 
    // skip the mouse buttons 
    return keyState.Skip(8).Any(state => (state & 0x80) != 0); 
} 
+0

Grazie per l'impegno, ma ottengo un'eccezione "EntryPointNotFound". Può essere dovuto a restrizioni di Windows 7, kernel diverso, non lo so. Inoltre, a basso livello (anche se questo sarebbe l'unico modo) ... –

+0

@Christian: nota che originariamente avevo specificato l'importazione sbagliata - Ho messo kernel32 ma dovrebbe essere user32. –

+0

@Christian: inoltre, ho aggiunto un 'Skip (8)' a 'AnyKeyPressed' in modo che non ritorni vero a causa della pressione dei pulsanti del mouse. –

0

casi in cui è presente il codice in esecuzione da? È in un gestore di eventi? Molte forme e controlli genereranno un evento KeyPress e un evento KeyDown. Potresti voler esaminare quegli eventi e impostare il tuo flag su true quando si verifica uno di questi. Dovresti anche ascoltare l'evento corrispondente che ti dice quando viene rilasciata la chiave (KeyUp, anche, penso).

0

Se si utilizza Windows.Forms, utilizzare l'evento KeyDown e leggere la chiave specifica utilizzando l'appropriato KeyEventArgs. È possibile accedere alla proprietà KeyCode sulla variabile KeyEventArgs.

Per controllare per i campi, dicono tra A e Z:

if (e.KeyCode>=Keys.A && e.KeyCode<=Keys.Z) 
{ 
    // do stuff...or not 
}
-1
normally I would use an event 

Si dovrebbe comunque utilizzare un evento, preferibilmente keydown dal momento che non vi occupate di quello tasto viene premuto, se si sta programmando Su Windows. In caso contrario, è possibile utilizzare qualcosa come Console.ReadLine();.

edit: Se siete alla ricerca di qualcosa di simile

if (Keyboard.IsKeyDown(Key.AnyKey)) return true; 

allora si deve essere scherzando ...

Edit 2: Beh, l'approccio del vostro logger è interessante, ma Penso che stai reinventando la ruota. Tutti i linguaggi di programmazione forniscono un modo per gestire il tasto premuto, quando questo può essere conosciuto. In C# per Windows, questo viene fatto usando gli eventi. Inoltre, penso che non sarai in grado di gestire questo tipo di cose da solo in .NET, dal momento che devi accedere ad alcune funzioni di sistema dall'API Win32 e AFAIK non ti è permesso farlo (almeno con facilità. ..) nel codice gestito. Qualche soluzione sarebbe quella di creare un HOOK e inviare messaggi da lì alla tua applicazione, ma non so come farlo in C#. Era così a Delphi, dove ho più esperienza.

+4

Non scherzando :-) Ma ovviamente la linea di pensiero sbagliata. Ma non lo trovo così inverosimile. Voglio dire, perché no, potrebbero esserci dei casi se voglio sapere se viene premuto QUALSIASI tasto. Modificata la voce, proverà il "logger" statico che può essere usato per il controllo ... –

+0

È possibile "inventare" questo tipo di stato chiave utilizzando gli eventi KeyUp e KeyDown in WinForms o WPF - sulla chiave giù aggiungere il premuto valore chiave per un elenco, su chiave, rimuoverlo - in qualsiasi momento puoi controllare se l'elenco contiene i valori che stai cercando e saprai se il tasto viene premuto o meno. – BrainSlugs83

0

È possibile incrementare un contatore per ogni evento keydown e decrementarlo per ciascun evento di keyup. Quando il contatore è zero, nessun tasto è premuto.

+0

Non possibile, gli eventi KeyDown vengono mangiati da alcuni elementi del WPF, e potrei non essere nemmeno nella mia app quando preme A. Quindi lo tengo, clicca sulla mia app, e non controlla che A sia premuto ... –

+3

Tu Stai guardando una casa. Una persona entra. Una persona esce. Una persona entra. Una persona esce. Una persona esce. Cosa concludete logicamente su questa sequenza di osservazioni? (1) ci sono -1 persone in casa, o (2) c'erano persone in casa prima che iniziassi a guardare? –

+1

@Eric: Direi che se qualcuno ora entra, la casa diventerà vuota. – Zano

3

Utilizzando il framework XNA è possibile utilizzare thw follow per verificare se è stato premuto un tasto.

Keyboard.GetState().GetPressedKeys().Length > 0 
+0

Perché qualsiasi utente desidera utilizzare il framework XNA solo per rilevare la pressione dei tasti? XNA è un client spesso destinato ad essere utilizzato per lo sviluppo di videogiochi – Rockstart

+2

Forse perché ciò che l'OP sta tentando di fare è tipicamente fatto solo nei videogiochi ... – BrainSlugs83

2

Piuttosto una vecchia questione, ma nel caso qualcuno si imbatte in questo e non vuole usare DLL esterna di, si può solo enumerare le possibili chiavi e anello su di loro.

bool IsAnyKeyPressed() 
    { 
     var allPossibleKeys = Enum.GetValues(typeof(Key)); 
     bool results = false; 
     foreach (var currentKey in allPossibleKeys) 
     { 
      Key key = (Key)currentKey; 
      if (key != Key.None) 
       if (Keyboard.IsKeyDown((Key)currentKey)) { results = true; break; } 
     } 
     return results; 
    } 

È possibile ottimizzare questo aspetto eseguendo l'enum al di fuori della funzione e conservando l'elenco per dopo.

Problemi correlati