Come rilevare il tasto attualmente premuto?


123

In Windows Forms puoi conoscere, in ogni momento, la posizione corrente del cursore grazie alla classe Cursors .

La stessa cosa non sembra essere disponibile per la tastiera. È possibile sapere se, ad esempio, Shiftviene premuto il tasto?

È assolutamente necessario rintracciare ogni notifica da tastiera (eventi KeyDown e KeyUp)?


Stai lavorando in un ambiente WPF o qualcos'altro?
epotter

70
@epotter: la seconda parola afferma WinForms.
Will Eddins

Risposte:


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

Questo sarà vero anche se Ctrl+ Shiftè in basso. Se vuoi controllare se è premuto Shift da solo,

if (Control.ModifierKeys == Keys.Shift)

Se ti trovi in ​​una classe che eredita Control(come un modulo), puoi rimuovere il fileControl.


8
A meno che non mi manchi qualcosa, non hai risposto correttamente alla domanda. L'OP chiede informazioni su tutti i tasti e ha utilizzato il tasto Maiusc solo come esempio. Quindi, come rilevi altri tasti come dalla A alla Z, dallo 0 al 9 ecc.
Ash

2
Dato che ha accettato la risposta, sembra che avesse bisogno solo dei tasti di modifica. Se vuoi altre chiavi, dovrai chiamare la GetKeyStatefunzione API.
SLaks

2
non c'è bisogno di GetKeyState. Hai solo bisogno di aggiungere un filtro dei messaggi. Vedi la mia risposta.
Ash

3
Per una soluzione WPF che puoi usare Keyboard.Modifiers == ModifierKeys.Shift (per quelli che sono venuti qui per una ricerca)
Bill Tarbell

3
invece di (Control.ModifierKeys & Keys.Shift) != 0uno può usareControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon

55

Il codice seguente spiega come rilevare quasi tutti i tasti attualmente premuti, non solo il Shifttasto.

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

1
GetKeyStatesarebbe più efficiente. Non ha senso tenere traccia di tutte le chiavi quando Windows lo fa già per te.
SLaks

3
@Slaks, a meno che tu non abbia alcuni dati di benchmark, stai indovinando. Inoltre GetKeyState ti dirà lo stato di una chiave, se puoi intercettare quell'evento della tastiera in primo luogo. La mia lettura della domanda è che l'OP vuole sapere come ottenere lo stato di una chiave in qualsiasi momento . Quindi GetKeyState da solo è inutile.
Ash

3
Come lo usereste esattamente per mostrare i tasti premuti?
Gabriel Ryan Nahmias

Gabriel: crea un'istanza di KeyMessageFilter come campo nel tuo modulo. Passalo a Application.AddMessageFilter () in Form_Load. Quindi chiama IsKeyPressed () su questa istanza per ogni / qualsiasi tasto a cui sei interessato.
Ash

@Ash, grazie per la tua risposta - saresti in grado di fare un esempio di codice per controllare il tasto SHIFT ecc.
BKSpurgeon

24

Puoi anche esaminare quanto segue se usi WPF o fai riferimento a System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

Lo spazio dei nomi Keyboard può essere utilizzato anche per controllare lo stato premuto di altri tasti con Keyboard.IsKeyDown (Key) o, se ti stai iscrivendo a un evento KeyDownEvent o simile, gli argomenti dell'evento contengono un elenco dei tasti attualmente premuti.


1
In realtà i Keyboard.Modifiers non funzionano sempre correttamente. Ho dovuto trovare il modo più duro: discoveringdotnet.alexeyev.org/2008/09/…
Maxim Alexeyev

Tranne che questo non sta usando i modificatori di Form, i modificatori System.Windows.Input sono uno spazio dei nomi diverso e hanno funzionato bene per noi ogni volta.
Jeff Wain

18

La maggior parte di queste risposte sono troppo complicate o non sembrano funzionare per me (ad esempio System.Windows.Input non sembra esistere). Poi ho trovato un codice di esempio che funziona bene: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Nel caso in cui la pagina scompaia in futuro, inserisco il codice sorgente pertinente di seguito:

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

3
System.Windows.Inputesiste; per gli altri che hanno problemi con questo è necessario aggiungere un riferimento a PresentationCoree un riferimento aggiuntivo a WindowsBaseper accedere System.Windows.Input.Keyall'enumerazione. Queste informazioni sono sempre disponibili su MSDN.
Alfie

1
Questa classe dovrebbe essere static, no abstract.
Little Endian

1
Il collegamento è interrotto (404).
Peter Mortensen,

2
"Nel caso in cui la pagina scompaia in futuro,
inserisco il

12

A partire da .NET Framework versione 3.0, è possibile utilizzare il Keyboard.IsKeyDownmetodo dal nuovo System.Windows.Inputspazio dei nomi. Per esempio:

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

Anche se fa parte di WPF, quel metodo funziona bene per le applicazioni WinForm (a condizione che si aggiungano riferimenti a PresentationCore.dll e WindowsBase.dll ). Sfortunatamente, tuttavia, le versioni 3.0 e 3.5 del Keyboard.IsKeyDownmetodo non funzionavano per le applicazioni WinForm. Pertanto, se si desidera utilizzarlo in un'applicazione WinForm, è necessario scegliere come target .NET Framework 4.0 o versioni successive affinché funzioni.


solo una nota, questo è solo per WPF
Diego Vieira

2
@DiegoVieira In realtà, non è vero. La funzionalità è stata aggiunta come parte di WPF e richiede che si faccia riferimento a tali librerie WPF, ma il Keyboard.IsKeyDownmetodo funziona, anche in un progetto WinForm.
Steven Doggart

Infatti, devi aggiungere PresentationCore.dll
Diego Vieira

2
Nota che questo non funziona (in WinForms) se il targeting è .Net 3.5 o precedente, solo 4.0+, a causa della modifica nell'implementazione di Win32KeyboardDevice.GetKeyStatesFromSystem (Key) :(
LMK

@ LMK Bella cattura. L'ho provato di persona e ho verificato quello che hai detto. Ho aggiornato la mia risposta per riflettere queste informazioni. Grazie!
Steven Doggart

8

Puoi P / Invoke fino al GetAsyncKeyState Win32 per testare qualsiasi tasto sulla tastiera.

È possibile passare valori dall'enumerazione Keys (ad esempio Keys.Shift) a questa funzione, quindi sono necessarie solo un paio di righe di codice per aggiungerla.


Keyboardnon è stato riconosciuto dal compilatore, ma GetAsyncKeystatein user32 ha funzionato bene. Grazie!
Einstein X. Mystery

5
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
     // CTRL+F pressed !
}

3

Il modo migliore che ho trovato per gestire l'input da tastiera su un modulo Windows Form è elaborarlo dopo la sequenza di tasti e prima che il controllo focalizzato riceva l'evento. Microsoft mantiene una Formproprietà di livello incorporata denominata .KeyPreview per facilitare questa cosa precisa:

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

Quindi è possibile eseguire il marshalling degli eventi _KeyDown, _KeyPress e / o _KeyUp del modulo per accedere agli eventi di input prima che il controllo del modulo focalizzato li veda mai, e puoi applicare la logica del gestore per catturare l'evento lì o consentirne il passaggio al controllo del modulo focalizzato .

Sebbene non sia strutturalmente elegante come l' architettura di instradamento degli eventi di XAML , rende la gestione delle funzioni a livello di modulo in Winforms molto più semplice. Vedere le note di MSDN su KeyPreview per avvertenze.


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

funziona per una casella di testo se il codice precedente è nell'evento keydown del modulo e nessun altro controllo acquisisce l'evento keydown per il tasto down.

Inoltre si potrebbe desiderare di interrompere l'ulteriore elaborazione delle chiavi con:

e.Handled = true;

2
if (Control.ModifierKeys == Keys.Shift)
    //Shift is pressed

La posizione x / y del cursore è una proprietà e la pressione di un tasto (come un clic del mouse / mousemove) è un evento. La migliore pratica è di solito lasciare che l'interfaccia sia guidata dagli eventi. L'unica volta in cui avresti bisogno di quanto sopra è se stai cercando di fare una cosa Maiusc + clic del mouse.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.