2009-11-17 6 views
10

[EDIT 3] je sorte de « résolu » par à l'aide de la version « étrange ». Au moins pour les clés les plus importantes. C'est suffisant pour mon cas, où je veux vérifier que ALT et ALT + A ne sont pas les mêmes (en s'assurant que A n'est pas enfoncé). Pas parfait, mais déjà beaucoup de temps pour un si petit problème. Merci pour toutes les réponses de toute façon ... [EDIT 3]détecter si une touche est enfoncée en C# (non A, B, mais tout)

[EDIT 4] a résolu le problème beaucoup plus propre grâce à 280Z28 [/ EDIT 4]

Je sais comment vérifier les touches de modification et comment pour tester une seule clé. Le problème est, je veux vérifier si une touche est pressée. L'approche suivante semble « étrange » :-)

WPF application écrite en C#

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

Je sais qu'il est un ENUM, donc je pensais à une boucle, mais ce qui est le « plus grand nombre » utiliser. Et est-ce possible? btw, c'est un cas très spécial, normalement j'utiliserais un événement, mais dans ce cas je dois le faire de cette façon. Malheureusement, il n'y a pas de "liste" Keyboard.CurrentlyDownKeys. Au moins, je ne l'ai pas vu.

Merci, Chris

EDIT: Ok, car il semble être une plus grande affaire, voici la raison: J'ai défini un « KeySet » qui sert DictionaryKey pour les fonctions personnalisées. Si quelqu'un clique sur un élément, le wrapper parcourt le dictionnaire et vérifie si l'un des "Keysets" prédéfinis est actif.

Cela me permet de définir des déclencheurs simples, comme par exemple Exécutez cette fonction si vous appuyez sur ALT + A + B. Une autre option est par exemple Exécutez cette fonction si vous appuyez sur ALT + STRG + A (lors d'un clic de souris sur un élément WPF). Le seul "problème" avec l'implémentation actuelle, si je définis un Keyset qui ne contient pas de clés REAL, comme si on appuie sur ALT, il est également déclenché si on appuie sur ALT + A. Oh, en écrivant ceci, je réalise qu'il y a un autre problème. ALT + A + B se déclencherait également si ALT + A + B + C est pressé.

Peut-être que mon approche est erronée, et je devrais créer un « outil de suivi clé statique » et comparer les keyset à ses valeurs (aquired par les événements) .. Je vais essayer ce.

EDIT 2 Cela ne fonctionne pas, du moins pas de manière simple. J'ai besoin d'un FrameworkElement pour attacher à KeyDown, mais je ne l'ai pas dans un constructeur statique. Et je ne suis pas intéressé par KeyDownEvents d'un certain élément, mais « globalement » ... Je pense que je saillir reporter ce problème, ce ne est pas si important que cela. Pourtant, si quelqu'un connaît une meilleure approche différente ...

Tant, pour tous ceux qui se soucie, voici un code:

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

Quelle est votre application? Console? Windows Forms? WPF? Site Internet? – jrista

+0

Voir le titre ... .NET C# –

+0

Cela n'aide pas. –

Répondre

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

Merci pour l'effort, mais j'ai une exception "EntryPointNotFound". Peut être dû à des restrictions de Windows 7, noyau différent, ne sais pas. Aussi, au niveau bas (même si ce serait le seul moyen) ... –

+0

@Christian: notez que j'ai d'abord eu la mauvaise importation spécifiée - je mets kernel32 mais c'est supposé être user32. –

+0

@Christian: aussi, j'ai ajouté 'Skip (8)' à 'AnyKeyPressed' afin qu'il ne retourne pas vrai en raison de l'appui sur les boutons de la souris. –

0

Où est ce code en cours d'exécution à partir? Est-ce dans un gestionnaire d'événements? De nombreux formulaires et contrôles déclenchent un événement KeyPress ainsi qu'un événement KeyDown. Vous pouvez vouloir regarder dans ces événements et mettre votre drapeau à vrai quand l'un d'eux se produit. Vous devrez également écouter l'événement correspondant qui vous indique quand la clé est libérée (KeyUp, aussi, je pense).

0

Si vous utilisez Windows.Forms, utilisez l'événement KeyDown et lisez la clé spécifique en utilisant le KeyEventArgs approprié. Vous pouvez accéder à la propriété KeyCode sur la variable KeyEventArgs.

Pour vérifier les plages, disons entre A et Z:

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

Vous devriez toujours utiliser un événement, de préférence KeyDown puisque vous ne me dérange pas ce que touche, si vous programmez sur les fenêtres. Sinon, vous pouvez utiliser quelque chose comme Console.ReadLine();.

modifier: Si vous cherchez quelque chose comme

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

vous plaisantez ...

modifier 2: Eh bien, l'approche de votre enregistreur est intéressant, mais Je pense que vous réinventez la roue. Tous les langages de programmation fournissent un moyen de gérer quelle touche a été pressée, quand cela peut être connu. En C# pour Windows, cela est fait en utilisant des événements. En outre, je pense que vous ne serez pas capable de gérer ce genre de choses par vous-même dans .NET, car vous devez accéder à certaines fonctions système de l'API Win32, et AFAIK vous n'êtes pas autorisé à le faire (au moins facilement. ..) dans le code managé. Une solution serait de créer un HOOK et d'envoyer des messages à votre application, mais je ne sais pas comment faire cela en C#. C'était le chemin à Delphes, où j'ai plus d'expérience.

+4

Ne plaisante pas :-) Mais évidemment mauvais train de pensée. Mais je ne trouve pas cela tiré par les cheveux. Je veux dire pourquoi pas, il pourrait y avoir des cas si je veux savoir si n'importe quelle touche est pressée. Edité l'entrée, va essayer le statique "logger" qui peut être utilisé pour vérifier ... –

+0

Vous pouvez "inventer" ce type d'état clé en utilisant les événements KeyUp et KeyDown dans WinForms ou WPF - sur la touche enfoncée ajouter le pressé la valeur d'une clé dans une liste, sur une touche enfoncée, supprimez-la - à tout moment, vous pouvez simplement vérifier si la liste contient les valeurs que vous recherchez et vous saurez si la touche est enfoncée ou non. – BrainSlugs83

0

http://sourceforge.net/projects/keystate/ affiche les touches "spéciales". Sinon, je pense que vous allez devoir les surveiller. Des fonds comme vous voulez faire cela dans tout le système? Qu'est-ce que vous essayez d'accomplir?

0

Vous pouvez incrémenter un compteur pour chaque événement de raccourci et le décrémenter pour chaque événement de touche. Lorsque le compteur est zéro, aucune touche n'est enfoncée.

+0

Impossible, les événements KeyDown sont mangés par certains éléments WPF, et je ne suis peut-être même pas dans mon application en appuyant sur A. Puis je le maintiens, cliquez sur mon application et il ne vérifie pas que A est pressé ... –

+3

You regarde une maison. Une personne entre. Une personne sort. Une personne entre. Une personne sort. Une personne sort. Que concluez-vous logiquement sur cette séquence d'observations? (1) il y a -1 personnes dans la maison, ou (2) il y avait des gens dans la maison avant que je commence à regarder? –

+1

@Eric: Je dirais que si quelqu'un entre maintenant, la maison deviendra vide. – Zano

3

Utilisation du framework XNA vous pouvez utiliser THW suivre pour vérifier si une touche a été enfoncée.

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

Pourquoi tout utilisateur souhaite utiliser XNA framework juste pour détecter leur touche de presse? XNA est un client épais destiné à être utilisé pour le développement de jeux vidéo – Rockstart

+2

Peut-être parce que ce que les PO essayent de faire est généralement fait uniquement dans les jeux vidéo ... – BrainSlugs83

2

Tout à fait une vieille question, mais dans le cas où quelqu'un vient à travers cela et ne veut pas utiliser dll externes, vous pouvez simplement énumérer les clés possibles et boucle sur eux.

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

Vous pouvez optimiser ce un peu en faisant l'ENUM en dehors de la fonction et de retenir la liste pour plus tard.

Questions connexes