O anda basılan tuş nasıl tespit edilir?


123

In Windows Forms , sen herhangi bir zamanda, imleç sayesinde mevcut konumu bilebilir imleçler sınıfında.

Aynı şey klavye için mevcut görünmüyor. Örneğin, Shifttuşuna basılıp basılmadığını bilmek mümkün mü ?

Her klavye bildirimini (KeyDown ve KeyUp olayları) izlemek kesinlikle gerekli mi?


Bir WPF ortamında mı yoksa başka bir şeyde mi çalışıyorsunuz?
epotter

70
@epotter: İkinci kelime WinForms'u belirtir.
Will Eddins

Yanıtlar:


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

Bu, Ctrl+ Shiftdüşürüldüğünde de geçerli olacaktır . Tek başına Shift'e basılıp basılmadığını kontrol etmek isterseniz,

if (Control.ModifierKeys == Keys.Shift)

Devralan bir sınıftaysanız Control(bir form gibi),Control.


8
Bir şeyi kaçırmadığım sürece, soruyu doğru cevaplamamışsınızdır. OP tüm tuşlar hakkında sorular soruyor ve sadece örnek olarak Shift tuşunu kullandı. Peki, A'dan Z'ye, 0'dan 9'a vb. Gibi diğer anahtarları nasıl tespit edersiniz?
Ash

2
Cevabı kabul ettiği göz önüne alındığında, sadece değiştirici tuşlara ihtiyacı olduğu anlaşılıyor. Başka anahtarlar istiyorsanız, GetKeyStateAPI işlevini çağırmanız gerekir .
SLaks

2
GetKeyState'e gerek yok. Sadece bir mesaj filtresi eklemeniz gerekiyor. Cevabımı gör.
Ash

3
Kullanabileceğiniz bir WPF çözümü için Keyboard.Modifiers == ModifierKeys.Shift (aramada buraya gelenler için)
Bill Tarbell

3
(Control.ModifierKeys & Keys.Shift) != 0biri yerine kullanılabilirControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon

55

Aşağıdaki kod, yalnızca Shiftanahtarın değil, hemen hemen tüm basılan tuşların nasıl tespit edileceğidir .

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
GetKeyStatedaha verimli olur. Windows sizin için zaten yaptığında tüm anahtarları izlemenin bir anlamı yoktur.
SLaks

3
@Slaks, bazı kıyaslama verileriniz yoksa, tahmin edersiniz. Üstelik GetKeyState, size bir anahtar durumunu anlatacağım eğer yapabilirsiniz tuzak olduğunu ilk etapta klavye olayı. Benim soruyu okumam, OP'nin herhangi bir zamanda bir anahtarın durumunu nasıl elde edeceğini bilmek istemesidir . Yani GetKeyState kendi başına işe yaramaz.
Ash

3
Basılan tuşları göstermek için bunu tam olarak nasıl kullanırsınız?
Gabriel Ryan Nahmias

Gabriel: Formunuzda bir alan olarak KeyMessageFilter örneği oluşturun. Form_Load'da Application.AddMessageFilter () öğesine aktarın. Ardından, ilgilendiğiniz her / herhangi bir anahtar için bu örnekte IsKeyPressed () arayın.
Ash

@Ash, cevabınız için teşekkürler - yukarıdaki SHIFT tuşunu vb. Kontrol etmek için bir kod örneği yapabilecek misiniz?
BKSpurgeon

24

WPF veya referans System.Windows.Input kullanıyorsanız aşağıdakilere de bakabilirsiniz.

if (Keyboard.Modifiers == ModifierKeys.Shift)

Keyboard.IsKeyDown (Key) ile diğer tuşların basılmış durumunu kontrol etmek için de Keyboard ad alanı kullanılabilir veya bir KeyDownEvent veya benzer bir olaya abone olursanız, olay argümanları o anda basılan tuşların bir listesini taşır.


1
Aslında Klavye Değiştiriciler her zaman düzgün çalışmaz. Zor yolu bulmak zorundaydım: discoveringdotnet.alexeyev.org/2008/09/…
Maxim Alexeyev

Bunun Forms değiştiricilerini kullanmaması dışında, System.Windows.Input değiştiricileri farklı bir ad alanıdır ve her seferinde bizim için iyi çalıştı.
Jeff Wain

18

Bu yanıtların çoğu ya çok karmaşık ya da benim için işe yaramıyor gibi görünüyor (örneğin, System.Windows.Input mevcut görünmüyor). Sonra iyi çalışan bazı örnek kodlar buldum: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Sayfanın ileride kaybolması durumunda ilgili kaynak kodunu aşağıya gönderiyorum:

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.Inputvardır; bununla mücadele eden diğerleri için bir referans eklemeniz ve numaralandırmaya erişmek için PresentationCoreek bir referans eklemeniz gerekir . Bu bilgi her zaman MSDN'de bulunabilir. WindowsBaseSystem.Windows.Input.Key
Alfie

1
Bu sınıfın olması gerekiyordu static, değil abstract.
Little Endian

1
Bağlantı koptu (404).
Peter Mortensen

2
"Sayfanın ileride kaybolması durumunda, ilgili kaynak kodunu aşağıya
gönderiyorum

12

.NET Framework sürüm 3.0'dan beri, Keyboard.IsKeyDownyöntemi yeni System.Windows.Inputad alanından kullanmak mümkündür . Örneğin:

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

WPF'nin bir parçası olsa da, bu yöntem WinForm uygulamaları için iyi çalışır ( PresentationCore.dll ve WindowsBase.dll'ye başvurular eklemeniz koşuluyla ). Ne yazık ki, ancak, Keyboard.IsKeyDownyöntemin 3.0 ve 3.5 sürümleri WinForm uygulamaları için çalışmadı. Bu nedenle, bir WinForm uygulamasında kullanmak istiyorsanız, çalışabilmesi için .NET Framework 4.0 veya sonrasını hedeflemeniz gerekir.


sadece bir not, bu sadece WPF için
Diego Vieira

2
@DiegoVieira Aslında bu doğru değil. İşlevsellik WPF'nin bir parçası olarak eklenmiştir ve bu WPF kitaplıklarına başvurulmasını gerektirir, ancak Keyboard.IsKeyDownyöntem bir WinForm projesinde bile çalışır.
Steven Doggart

Gerçekten, PresentationCore.dll
Diego Vieira

2
Win32KeyboardDevice.GetKeyStatesFromSystem (Anahtar) uygulamasındaki değişiklik nedeniyle .Net 3.5 veya önceki bir sürümü hedefleniyorsa (WinForms'ta) bunun işe yaramadığını unutmayın :(
LMK

@LMK Güzel yakalayış. Kendim test ettim ve söylediklerini doğruladım. Cevabımı bu bilgiyi yansıtacak şekilde güncelledim. Teşekkürler!
Steven Doggart

8

Şunları yapabilirsiniz P / çağır aşağı Win32 için GetAsyncKeyState herhangi bir tuşu test .

Keys numaralandırmasından (örn. Keys.Shift) bu işleve değer iletebilirsiniz, bu nedenle eklemek için yalnızca birkaç satır kod gerektirir.


Keyboardderleyici tarafından tanınmadı, ancak GetAsyncKeystateuser32'de gayet iyi çalıştı. Teşekkürler!
Einstein X. Mystery

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

3

Bir Windows Forms formunda klavye girişini yönetmenin en iyi yolu, onu tuş vuruşundan sonra ve odaklanmış denetim olayı almadan önce işlemektir. Microsoft, bu kesin şeyi kolaylaştırmak için .KeyPreviewForm adında yerleşik bir özellik bulundurmaktadır :

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

Ardından, formun _KeyDown, _KeyPress ve / veya _KeyUp olayları, odaklanmış form denetimi onları görmeden giriş olaylarına erişmek için sıralanabilir ve olayı orada yakalamak veya odaklanmış form denetimine geçmesine izin vermek için işleyici mantığı uygulayabilirsiniz. .

XAML'in olay yönlendirme mimarisi kadar yapısal olarak zarif olmasa da , Winforms'taki form düzeyindeki işlevlerin yönetimini çok daha basit hale getirir. Uyarılar için KeyPreview üzerindeki MSDN notlarına bakın .


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

Yukarıdaki kod formun keydown olayındaysa ve başka hiçbir kontrol tuş aşağı için keydown olayını yakalamazsa bir metin kutusu için çalışır.

Ayrıca aşağıdakilerle daha fazla anahtar işlemeyi durdurmak isteyebilirsiniz:

e.Handled = true;

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

İmleç x / y konumu bir özelliktir ve bir tuşa basma (fare tıklaması / mousemove gibi) bir olaydır. En iyi uygulama genellikle arayüzün olay odaklı olmasına izin vermektir. Yukarıdakilere ihtiyaç duyacağınız tek zaman, bir vardiya + fare tıklaması yapmaya çalışmanızdır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.