Làm thế nào để phát hiện phím đang nhấn?


123

Trong Windows Forms , bạn có thể biết, bất cứ lúc nào, vị trí hiện tại của con trỏ nhờ vào lớp Con trỏ .

Điều tương tự dường như không có sẵn cho bàn phím. Có thể biết nếu, ví dụ, Shiftphím được nhấn?

Có nhất thiết phải theo dõi mọi thông báo bàn phím (sự kiện KeyDown và KeyUp) không?


Bạn đang làm việc trong môi trường WPF hay cái gì khác?
epotter

70
@epotter: Từ thứ hai nói WinForms.
Will Eddins

Câu trả lời:


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

Điều này cũng sẽ đúng nếu Ctrl+ không hoạt Shiftđộng. Nếu bạn muốn kiểm tra xem Shift có được nhấn hay không,

if (Control.ModifierKeys == Keys.Shift)

Nếu bạn đang ở trong một lớp kế thừa Control(chẳng hạn như một biểu mẫu), bạn có thể xóaControl.


8
Trừ khi tôi thiếu một cái gì đó, bạn chưa trả lời đúng câu hỏi. OP đang hỏi về tất cả các khóa và chỉ sử dụng phím Shift làm ví dụ. Vậy làm thế nào để bạn phát hiện các khóa khác như A đến Z, 0 đến 9, v.v.
Ash

2
Cho rằng anh ta đã chấp nhận câu trả lời, có vẻ như anh ta chỉ cần các phím bổ trợ. Nếu bạn muốn các khóa khác, bạn sẽ cần gọi GetKeyStatehàm API.
SLaks

2
không cần GetKeyState. Bạn chỉ cần thêm một bộ lọc tin nhắn. Xem câu trả lời của tôi.
Tro

2
Đối với giải pháp WPF, bạn có thể sử dụng Keyboard.Modifiers == ModifierKeys.Shift (đối với những giải pháp đã xuất hiện ở đây trên một tìm kiếm)
Bill Tarbell

3
thay vì (Control.ModifierKeys & Keys.Shift) != 0người ta có thể sử dụngControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon

55

Mã dưới đây là cách phát hiện gần như tất cả các phím hiện đang được nhấn, không chỉ Shiftphím.

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
GetKeyStatesẽ hiệu quả hơn Không có điểm nào trong việc theo dõi tất cả các khóa khi Windows đã làm điều đó cho bạn.
SLaks

3
@Slaks, trừ khi bạn có một số dữ liệu điểm chuẩn, bạn sẽ đoán. Ngoài ra, GetKeyState sẽ cho bạn biết trạng thái của một phím, nếu bạn có thể bẫy sự kiện bàn phím đó ở vị trí đầu tiên. Tôi đọc câu hỏi này là OP muốn biết làm thế nào để có được trạng thái của khóa bất cứ lúc nào . Vì vậy, GetKeyState tự nó là vô dụng.
Tro

3
Làm thế nào chính xác bạn sẽ sử dụng điều này để hiển thị các phím được nhấn?
Gabriel Ryan Nahmias

Gabriel: Tạo một thể hiện của KeyMessageFilter dưới dạng một trường trong biểu mẫu của bạn. Truyền nó cho Application.AddMessageFilter () trong Form_Load. Sau đó gọi IsKeyPression () trong trường hợp này cho mỗi / bất kỳ khóa nào bạn quan tâm.
Ash

@Ash cảm ơn câu trả lời của bạn - bạn có thể làm một ví dụ mã để kiểm tra phím SHIFT, v.v. ở trên không?
BKSpurgeon

23

Bạn cũng có thể xem các mục sau nếu bạn tham khảo System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

Không gian tên Bàn phím cũng có thể được sử dụng để kiểm tra trạng thái nhấn của các phím khác bằng Bàn phím.IsKeyDown (Khóa) hoặc nếu bạn đang đăng ký một KeyDownEvent hoặc sự kiện tương tự, các đối số sự kiện mang danh sách các phím hiện được nhấn.


1
Trên thực tế Bàn phím. Bộ điều chế không phải lúc nào cũng hoạt động đúng. Phải tìm cách khó khăn: khám
phádotnet.alexeyev.org / 2008/09 / Kẻ

Ngoại trừ việc này không sử dụng công cụ sửa đổi Biểu mẫu, công cụ sửa đổi System.Windows.Input là một không gian tên khác nhau và đã hoạt động tốt cho chúng tôi mỗi lần.
Jeff Wain

18

Hầu hết các câu trả lời này quá phức tạp hoặc dường như không phù hợp với tôi (ví dụ System.Windows.Input dường như không tồn tại). Sau đó, tôi tìm thấy một số mã mẫu hoạt động tốt: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Trong trường hợp trang biến mất trong tương lai, tôi sẽ đăng mã nguồn có liên quan bên dưới:

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.Inputtồn tại; đối với những người khác đang vật lộn với điều này, bạn cần thêm một tài liệu tham khảo PresentationCorevà một tài liệu tham khảo bổ sung WindowsBaseđể truy cập System.Windows.Input.Keybảng liệt kê. Thông tin này luôn có thể được tìm thấy trên MSDN.
Alfie

1
Lớp học này được cho là static, không abstract.
Little Endian

1
Liên kết bị hỏng (404).
Peter Mortensen

2
"Trong trường hợp trang biến mất trong tương lai, tôi sẽ đăng mã nguồn có liên quan bên dưới"
Parsley72

12

Kể từ .NET Framework phiên bản 3.0, có thể sử dụng Keyboard.IsKeyDownphương thức từ System.Windows.Inputkhông gian tên mới . Ví dụ:

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

Mặc dù đó là một phần của WPF, phương pháp đó hoạt động tốt cho các ứng dụng WinForm (miễn là bạn thêm các tham chiếu đến PresentationCore.dllWindowsBase.dll ). Thật không may, tuy nhiên, phiên bản 3.0 và 3.5 của Keyboard.IsKeyDownphương thức không hoạt động cho các ứng dụng WinForm. Do đó, nếu bạn muốn sử dụng nó trong ứng dụng WinForm, bạn sẽ cần nhắm mục tiêu .NET Framework 4.0 trở lên để nó hoạt động.


chỉ là một lưu ý, đây chỉ dành cho WPF
Diego Vieira

2
@DiegoVieira Thật ra, điều đó không đúng. Chức năng đã được thêm vào như một phần của WPF và nó yêu cầu các thư viện WPF đó được tham chiếu, nhưng Keyboard.IsKeyDownphương thức này hoạt động, ngay cả trong một dự án WinForm.
Steven Doggart

Thật vậy, bạn phải thêm PresentationCore.dll
Diego Vieira

2
Lưu ý điều này không hoạt động (trong WinForms) nếu nhắm mục tiêu .Net 3.5 trở về trước, chỉ 4.0+, do thay đổi trong quá trình triển khai Win32PalDevice.GetKeyStatesFromSystem (Khóa) :(
LMK

@LMK Bắt đẹp. Tôi đã tự kiểm tra và xác minh những gì bạn nói. Tôi cập nhật câu trả lời của tôi để phản ánh thông tin đó. Cảm ơn!
Steven Doggart

8

Bạn có thể P / Gọi xuống Win32 GetAsyncKeyState để kiểm tra bất kỳ phím nào trên bàn phím.

Bạn có thể chuyển các giá trị từ enum Keys (ví dụ: Keys.Shift) cho hàm này, vì vậy nó chỉ yêu cầu một vài dòng mã để thêm nó.


Keyboardkhông được trình biên dịch nhận ra, nhưng GetAsyncKeystatetrong user32 hoạt động tốt. Cảm ơn!
Einstein X. Bí ẩn

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

3

Cách tốt nhất mà tôi đã tìm thấy để quản lý đầu vào bàn phím trên biểu mẫu Windows Forms là xử lý nó sau khi nhấn phím và trước khi điều khiển tập trung nhận được sự kiện. Microsoft duy trì một thuộc Formtính tích hợp sẵn có tên .KeyPreview để tạo điều kiện thuận lợi cho điều chính xác này:

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

Sau đó, các sự kiện _KeyDown, _KeyPress và / hoặc _KeyUp của biểu mẫu có thể được sắp xếp để truy cập các sự kiện đầu vào trước khi điều khiển biểu mẫu tập trung nhìn thấy chúng và bạn có thể áp dụng logic xử lý để nắm bắt sự kiện ở đó hoặc cho phép nó chuyển qua điều khiển biểu mẫu tập trung .

Mặc dù không có cấu trúc duyên dáng như kiến trúc định tuyến sự kiện của XAML , nhưng nó giúp cho việc quản lý các hàm mức biểu mẫu trong Winforms trở nên đơn giản hơn rất nhiều. Xem ghi chú MSDN trên KeyPreview để biết thêm.


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

không hoạt động đối với hộp văn bản nếu đoạn mã trên nằm trong sự kiện khóa phím của biểu mẫu và không có điều khiển nào khác ghi lại sự kiện phím tắt cho phím tắt.

Ngoài ra người ta có thể muốn dừng xử lý khóa tiếp theo với:

e.Handled = true;

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

Vị trí con trỏ x / y là một thuộc tính và nhấn phím (như nhấp chuột / mousemove) là một sự kiện. Thực hành tốt nhất thường là để cho giao diện được điều khiển sự kiện. Về thời gian duy nhất bạn cần ở trên là nếu bạn đang cố gắng làm một ca + mouseclick.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.