Wie erkenne ich die aktuell gedrückte Taste?

123

In Windows Forms können Sie dank der Cursors- Klasse jederzeit die aktuelle Position des Cursors ermitteln .

Dasselbe scheint für die Tastatur nicht verfügbar zu sein. Kann man wissen, ob zum Beispiel die ShiftTaste gedrückt wird?

Ist es unbedingt erforderlich, jede Tastaturbenachrichtigung (KeyDown- und KeyUp-Ereignisse) aufzuspüren?

Peter Mortensen
quelle
Arbeiten Sie in einer WPF-Umgebung oder in etwas anderem?
Epotter
70
@epotter: Das zweite Wort besagt WinForms.
Will Eddins

Antworten:

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

Dies gilt auch, wenn Ctrl+ nicht verfügbar Shiftist. Wenn Sie überprüfen möchten, ob nur die Umschalttaste gedrückt ist,

if (Control.ModifierKeys == Keys.Shift)

Wenn Sie sich in einer Klasse befinden, die erbt Control(z. B. ein Formular), können Sie das entfernenControl.

SLaks
quelle
8
Sofern mir nichts fehlt, haben Sie die Frage nicht richtig beantwortet. Das OP fragt nach allen Tasten und verwendet die Umschalttaste nur als Beispiel. Wie erkennt man andere Tasten wie A bis Z, 0 bis 9 usw.
Ash
2
Da er die Antwort akzeptiert hat, scheint er nur Modifikatortasten benötigt zu haben. Wenn Sie andere Schlüssel wünschen, müssen Sie die GetKeyStateAPI-Funktion aufrufen .
SLaks
2
GetKeyState ist nicht erforderlich. Sie müssen nur einen Nachrichtenfilter hinzufügen. Siehe meine Antwort.
Ash
2
Für eine WPF-Lösung können Sie verwenden Keyboard.Modifiers == ModifierKeys.Shift (für diejenigen, die hier auf einer Suche kamen)
Bill Tarbell
3
statt (Control.ModifierKeys & Keys.Shift) != 0man kann verwendenControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon
55

Mit dem folgenden Code können fast alle aktuell gedrückten Tasten erkannt werden, nicht nur die ShiftTaste.

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;
    }
}
Asche
quelle
1
GetKeyStatewäre effizienter. Es macht keinen Sinn, alle Schlüssel zu verfolgen, wenn Windows dies bereits für Sie erledigt.
SLaks
3
@ Slaks, wenn Sie keine Benchmark-Daten haben, raten Sie. Außerdem teilt Ihnen GetKeyState den Status einer Taste mit, wenn Sie dieses Tastaturereignis überhaupt abfangen können. Ich lese die Frage so, dass das OP jederzeit wissen möchte, wie es den Status eines Schlüssels erhält . GetKeyState an sich ist also nutzlos.
Ash
3
Wie genau würden Sie dies verwenden, um die gedrückten Tasten anzuzeigen?
Gabriel Ryan Nahmias
Gabriel: Erstellen Sie eine Instanz von KeyMessageFilter als Feld in Ihrem Formular. Übergeben Sie es an Application.AddMessageFilter () in Form_Load. Rufen Sie dann IsKeyPressed () auf dieser Instanz für jeden Schlüssel auf, an dem Sie interessiert sind.
Ash
@Ash danke für deine Antwort - könntest du ein Codebeispiel für die Suche nach der UMSCHALTTASTE usw. oben machen?
BKSpurgeon
23

Sie können sich auch Folgendes ansehen, wenn Sie auf System.Windows.Input verweisen

if (Keyboard.Modifiers == ModifierKeys.Shift)

Der Keyboard-Namespace kann auch verwendet werden, um den Status anderer Tasten mit Keyboard.IsKeyDown (Key) zu überprüfen. Wenn Sie ein KeyDownEvent oder ein ähnliches Ereignis abonnieren, enthalten die Ereignisargumente eine Liste der aktuell gedrückten Tasten.

Jeff Wain
quelle
1
Eigentlich funktionieren Keyboard.Modifiers nicht immer richtig. Musste den harten Weg finden: Discoveringdotnet.alexeyev.org/2008/09/…
Maxim Alexeyev
Abgesehen davon, dass keine Forms-Modifikatoren verwendet werden, handelt es sich bei System.Windows.Input-Modifikatoren um einen anderen Namespace, der bei uns jedes Mal einwandfrei funktioniert hat.
Jeff Wain
18

Die meisten dieser Antworten sind entweder viel zu kompliziert oder scheinen für mich nicht zu funktionieren (z. B. System.Windows.Input scheint nicht zu existieren). Dann habe ich einen Beispielcode gefunden, der gut funktioniert: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Für den Fall, dass die Seite in Zukunft verschwindet, veröffentliche ich den entsprechenden Quellcode unten:

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);
    }
  }
}
Petersilie72
quelle
3
System.Windows.Inputexistiert; Für andere, die damit zu kämpfen haben, müssen Sie einen Verweis auf PresentationCoreund einen zusätzlichen Verweis auf hinzufügen , WindowsBaseum auf die System.Windows.Input.KeyAufzählung zuzugreifen . Diese Informationen finden Sie immer auf MSDN.
Alfie
1
Diese Klasse soll es staticnicht sein abstract.
Little Endian
1
Die Verbindung ist unterbrochen (404).
Peter Mortensen
2
"Für den Fall, dass die Seite in Zukunft verschwindet, veröffentliche ich den entsprechenden Quellcode unten"
Petersilie72
12

Seit .NET Framework Version 3.0 ist es möglich, die Keyboard.IsKeyDownMethode aus dem neuen System.Windows.InputNamespace zu verwenden. Zum Beispiel:

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

Obwohl diese Methode Teil von WPF ist, funktioniert sie für WinForm-Anwendungen einwandfrei (vorausgesetzt, Sie fügen Verweise auf PresentationCore.dll und WindowsBase.dll hinzu ). Leider Keyboard.IsKeyDownfunktionierten die Versionen 3.0 und 3.5 der Methode für WinForm-Anwendungen nicht. Wenn Sie es daher in einer WinForm-Anwendung verwenden möchten, müssen Sie auf .NET Framework 4.0 oder höher abzielen, damit es funktioniert.

Steven Doggart
quelle
Nur eine Anmerkung, dies ist nur für WPF
Diego Vieira
2
@DiegoVieira Eigentlich stimmt das nicht. Die Funktionalität wurde als Teil von WPF hinzugefügt und erfordert, dass auf diese WPF-Bibliotheken verwiesen wird, aber die Keyboard.IsKeyDownMethode funktioniert auch in einem WinForm-Projekt.
Steven Doggart
In der Tat müssen Sie PresentationCore.dll
Diego Vieira
2
Beachten Sie, dass dies nicht funktioniert (in WinForms), wenn Sie auf .NET 3.5 oder früher (nur 4.0+) abzielen, da sich die Implementierung von Win32KeyboardDevice.GetKeyStatesFromSystem (Key) geändert hat :(
LMK
@LMK Schöner Fang. Ich habe es selbst getestet und überprüft, was Sie gesagt haben. Ich habe meine Antwort aktualisiert, um diese Informationen wiederzugeben. Vielen Dank!
Steven Doggart
8

Sie können P / Invoke bis zum Win32 GetAsyncKeyState ausführen , um eine beliebige Taste auf der Tastatur zu testen.

Sie können dieser Funktion Werte aus der Keys-Enumeration (z. B. Keys.Shift) übergeben, sodass nur ein paar Codezeilen erforderlich sind, um sie hinzuzufügen.

Jason Williams
quelle
Keyboardwurde vom Compiler nicht erkannt, GetAsyncKeystatefunktionierte aber in user32 einwandfrei. Vielen Dank!
Einstein X. Mystery
5
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
     // CTRL+F pressed !
}
Mahdi
quelle
3

Der beste Weg, um Tastatureingaben in einem Windows Forms-Formular zu verwalten, besteht darin, sie nach dem Tastendruck und bevor das fokussierte Steuerelement das Ereignis empfängt, zu verarbeiten. Microsoft verwaltet eine integrierte FormLevel-Eigenschaft namens .KeyPreview , um genau dies zu ermöglichen:

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

Anschließend können die _KeyDown-, _KeyPress- und / oder _KeyUp-Ereignisse des Formulars gemarshallt werden, um auf Eingabeereignisse zuzugreifen, bevor das fokussierte Formularsteuerelement sie jemals sieht, und Sie können die Handlerlogik anwenden, um das Ereignis dort zu erfassen oder es an das fokussierte Formularsteuerelement weiterzuleiten .

Obwohl es strukturell nicht so elegant ist wie die Event-Routing-Architektur von XAML, vereinfacht es die Verwaltung von Funktionen auf Formularebene in Winforms erheblich. Weitere Informationen finden Sie in den MSDN-Hinweisen zu KeyPreview .

Hardryv
quelle
2
if (Form.ModifierKeys == Keys.Shift)

funktioniert für ein Textfeld, wenn sich der obige Code im Keydown-Ereignis des Formulars befindet und kein anderes Steuerelement das Keydown-Ereignis für den Schlüssel nach unten erfasst.

Man kann auch wünschen, die weitere Schlüsselverarbeitung zu stoppen mit:

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

Die x / y-Position des Cursors ist eine Eigenschaft, und ein Tastendruck (wie ein Mausklick / eine Mausbewegung) ist ein Ereignis. Die beste Vorgehensweise besteht normalerweise darin, die Schnittstelle ereignisgesteuert zu lassen. Das einzige Mal, dass Sie das oben Genannte benötigen, ist, wenn Sie versuchen, eine Schicht + Mausklick-Sache zu machen.

Rob Elliott
quelle