Comment détecter la touche actuellement enfoncée?

123

Dans Windows Forms , vous pouvez connaître, à tout moment, la position actuelle du curseur grâce à la classe Cursors .

La même chose ne semble pas être disponible pour le clavier. Est-il possible de savoir si, par exemple, la Shifttouche est enfoncée?

Est-il absolument nécessaire de retrouver chaque notification clavier (événements KeyDown et KeyUp)?

Peter Mortensen
la source
Travaillez-vous dans un environnement WPF ou autre chose?
epotter
70
@epotter: le deuxième mot indique WinForms.
Will Eddins

Réponses:

162
if ((Control.ModifierKeys & Keys.Shift) != 0) 

Cela sera également vrai si Ctrl+ Shiftest en panne. Si vous voulez vérifier si Shift seul est enfoncé,

if (Control.ModifierKeys == Keys.Shift)

Si vous êtes dans une classe qui hérite Control(comme un formulaire), vous pouvez supprimer leControl.

SLaks
la source
8
À moins que je ne manque quelque chose, vous n'avez pas répondu correctement à la question. L'OP demande toutes les touches et a utilisé la touche Shift à titre d'exemple uniquement. Alors, comment détectez-vous d'autres clés telles que A à Z, 0 à 9, etc.
Ash
2
Étant donné qu'il a accepté la réponse, il semble qu'il n'avait besoin que de touches de modification. Si vous voulez d'autres clés, vous devrez appeler la GetKeyStatefonction API.
SLaks
2
pas besoin de GetKeyState. Il vous suffit d'ajouter un filtre de message. Voyez ma réponse.
Ash
3
Pour une solution WPF que vous pouvez utiliser Keyboard.Modifiers == ModifierKeys.Shift (pour ceux qui sont venus ici lors d'une recherche)
Bill Tarbell
3
au lieu d' (Control.ModifierKeys & Keys.Shift) != 0un peut utiliserControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon
55

Le code ci-dessous explique comment détecter presque toutes les touches actuellement enfoncées, pas seulement la Shifttouche.

private KeyMessageFilter m_filter = new KeyMessageFilter();

private void Form1_Load(object sender, EventArgs e)
{
    Application.AddMessageFilter(m_filter);
}


public class KeyMessageFilter : IMessageFilter
{
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_KEYUP = 0x0101;
    private bool m_keyPressed = false;

    private Dictionary<Keys, bool> m_keyTable = new Dictionary<Keys, bool>();

    public Dictionary<Keys, bool> KeyTable
    {
        get { return m_keyTable; }
        private set { m_keyTable = value; }
    }

    public bool IsKeyPressed()
    {
        return m_keyPressed;
    }

    public bool IsKeyPressed(Keys k)
    {
        bool pressed = false;

        if (KeyTable.TryGetValue(k, out pressed))
        {
            return pressed;
        }

        return false;
    }

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_KEYDOWN)
        {
            KeyTable[(Keys)m.WParam] = true;

            m_keyPressed = true;
        }

        if (m.Msg == WM_KEYUP)
        {
            KeyTable[(Keys)m.WParam] = false;

            m_keyPressed = false;
        }

        return false;
    }
}
Cendre
la source
1
GetKeyStateserait plus efficace. Il ne sert à rien de suivre toutes les clés lorsque Windows le fait déjà pour vous.
SLaks
3
@Slaks, à moins que vous n'ayez des données de référence, vous devinez. De plus, GetKeyState vous indiquera l'état d'une touche, si vous pouvez intercepter cet événement de clavier en premier lieu. Ma lecture de la question est que l'OP veut savoir comment obtenir l'état d'une clé à tout moment . Donc GetKeyState en lui-même est inutile.
Ash
3
Comment l'utiliseriez-vous exactement pour afficher les touches enfoncées?
Gabriel Ryan Nahmias
Gabriel: Créez une instance de KeyMessageFilter en tant que champ dans votre formulaire. Passez-le à Application.AddMessageFilter () dans Form_Load. Appelez ensuite IsKeyPressed () sur cette instance pour chaque clé qui vous intéresse.
Ash
@Ash merci pour votre réponse - seriez-vous capable de faire un exemple de code pour vérifier la touche SHIFT, etc. ci-dessus?
BKSpurgeon
24

Vous pouvez également consulter les éléments suivants si vous utilisez WPF ou référencez System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

L'espace de noms Keyboard peut également être utilisé pour vérifier l'état enfoncé d'autres touches avec Keyboard.IsKeyDown (Key), ou si vous vous abonnez à un KeyDownEvent ou à un événement similaire, les arguments d'événement contiennent une liste des touches actuellement enfoncées.

Jeff Wain
la source
1
En fait, Keyboard.Modifiers ne fonctionne pas toujours correctement. J'ai dû trouver le chemin difficile: discoveringdotnet.alexeyev.org/2008/09/…
Maxim Alexeyev
Sauf que cela n'utilise pas de modificateurs Forms, les modificateurs System.Windows.Input sont un espace de noms différent et ont bien fonctionné pour nous à chaque fois.
Jeff Wain
18

La plupart de ces réponses sont soit beaucoup trop compliquées, soit ne semblent pas fonctionner pour moi (par exemple, System.Windows.Input ne semble pas exister). Ensuite, j'ai trouvé un exemple de code qui fonctionne bien: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Au cas où la page disparaîtrait à l'avenir, je poste le code source pertinent ci-dessous:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MouseKeyboardStateTest
{
  public abstract class Keyboard
  {
    [Flags]
    private enum KeyStates
    {
      None = 0,
      Down = 1,
      Toggled = 2
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    private static extern short GetKeyState(int keyCode);

    private static KeyStates GetKeyState(Keys key)
    {
      KeyStates state = KeyStates.None;

      short retVal = GetKeyState((int)key);

      //If the high-order bit is 1, the key is down
      //otherwise, it is up.
      if ((retVal & 0x8000) == 0x8000)
        state |= KeyStates.Down;

      //If the low-order bit is 1, the key is toggled.
      if ((retVal & 1) == 1)
        state |= KeyStates.Toggled;

      return state;
    }

    public static bool IsKeyDown(Keys key)
    { 
      return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
    }

    public static bool IsKeyToggled(Keys key)
    { 
      return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
    }
  }
}
persil72
la source
3
System.Windows.Inputexiste; pour les autres, vous devez ajouter une référence à PresentationCoreet une référence supplémentaire à WindowsBasepour accéder à l' System.Windows.Input.Keyénumération. Cette information peut toujours être trouvée sur MSDN.
Alfie
1
Cette classe est censée l'être static, non abstract.
Little Endian
1
Le lien est rompu (404).
Peter Mortensen
2
"Au cas où la page disparaîtrait à l'avenir, je poste le code source pertinent ci-dessous"
persil72
12

Depuis .NET Framework version 3.0, il est possible d'utiliser la Keyboard.IsKeyDownméthode à partir du nouvel System.Windows.Inputespace de noms. Par exemple:

if (((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
{
    // CTRL + F is currently pressed
}

Même si elle fait partie de WPF, cette méthode fonctionne bien pour les applications WinForm (à condition que vous ajoutiez des références à PresentationCore.dll et WindowsBase.dll ). Malheureusement, les versions 3.0 et 3.5 de la Keyboard.IsKeyDownméthode ne fonctionnaient pas pour les applications WinForm. Par conséquent, si vous souhaitez l'utiliser dans une application WinForm, vous devez cibler .NET Framework 4.0 ou version ultérieure pour qu'il fonctionne.

Steven Doggart
la source
juste une note, ceci est pour WPF uniquement
Diego Vieira
2
@DiegoVieira En fait, ce n'est pas vrai. La fonctionnalité a été ajoutée dans le cadre de WPF et nécessite que ces bibliothèques WPF soient référencées, mais la Keyboard.IsKeyDownméthode fonctionne, même dans un projet WinForm.
Steven Doggart
En effet, vous devez ajouter PresentationCore.dll
Diego Vieira
2
Notez que cela ne fonctionne pas (dans WinForms) si vous ciblez .Net 3.5 ou version antérieure, seulement 4.0+, en raison du changement dans l'implémentation de Win32KeyboardDevice.GetKeyStatesFromSystem (Key) :(
LMK
@LMK Belle prise. Je l'ai testé moi-même et vérifié ce que vous avez dit. J'ai mis à jour ma réponse pour refléter cette information. Merci!
Steven Doggart
8

Vous pouvez P / Invoke jusqu'à Win32 GetAsyncKeyState pour tester n'importe quelle touche du clavier.

Vous pouvez passer des valeurs de l'énumération Keys (par exemple Keys.Shift) à cette fonction, donc il ne faut que quelques lignes de code pour l'ajouter.

Jason Williams
la source
Keyboardn'a pas été reconnu par le compilateur, mais GetAsyncKeystatedans user32 a très bien fonctionné. Merci!
Einstein X. Mystery
5
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
     // CTRL+F pressed !
}
Mahdi
la source
3

Le meilleur moyen que j'ai trouvé pour gérer l'entrée au clavier sur un formulaire Windows Forms est de le traiter après la frappe et avant que le contrôle ciblé ne reçoive l'événement. Microsoft gère une Formpropriété de niveau intégrée nommée .KeyPreview pour faciliter cette opération précise:

public frmForm()
{
    // ...
    frmForm.KeyPreview = true;
    // ...
}

Ensuite, les événements _KeyDown, _KeyPress et / ou _KeyUp du formulaire peuvent être marshalés pour accéder aux événements d'entrée avant que le contrôle de formulaire focalisé ne les voit, et vous pouvez appliquer la logique du gestionnaire pour capturer l'événement là-bas ou lui permettre de passer au contrôle de formulaire ciblé .

Bien que pas aussi structurellement gracieux que l' architecture de routage d' événements de XAML , il simplifie beaucoup la gestion des fonctions au niveau du formulaire dans Winforms. Consultez les notes MSDN sur KeyPreview pour les mises en garde.

Hardryv
la source
2
if (Form.ModifierKeys == Keys.Shift)

fonctionne pour une zone de texte si le code ci-dessus est dans l'événement keydown du formulaire et qu'aucun autre contrôle ne capture l'événement keydown pour la touche down.

On peut également souhaiter arrêter le traitement des clés avec:

e.Handled = true;
gg
la source
2
if (Control.ModifierKeys == Keys.Shift)
    //Shift is pressed

La position x / y du curseur est une propriété et une pression sur une touche (comme un clic de souris / souris) est un événement. La meilleure pratique consiste généralement à laisser l'interface être pilotée par les événements. À peu près le seul moment où vous auriez besoin de ce qui précède est si vous essayez de faire une opération shift + souris.

Rob Elliott
la source