Як виявити натиснуту клавішу?


123

У Windows Forms ви можете в будь-який час дізнатися про поточне положення курсору завдяки класу Cursors .

Це ж здається недоступним для клавіатури. Чи можна знати, чи Shiftнатискається , наприклад, клавіша?

Чи абсолютно необхідно відстежувати кожне повідомлення клавіатури (KeyDown та KeyUp події)?


Ви працюєте в середовищі WPF чи щось інше?
epotter

70
@epotter: Друге слово констатує WinForms.
Вілл Еддінс

Відповіді:


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

Це також буде вірно, якщо Ctrl+ Shiftвниз. Якщо ви хочете перевірити, чи натиснуто лише Shift,

if (Control.ModifierKeys == Keys.Shift)

Якщо ви перебуваєте в класі, який успадковує Control(наприклад, форму), ви можете видалитиControl.


8
Якщо я щось не пропускаю, ви не відповіли належним чином на питання. ОП запитує про всі клавіші і використовує клавішу Shift лише як приклад. Тож як ви можете виявити інші клавіші, такі як від A до Z, від 0 до 9 тощо
Еш

2
Зважаючи на те, що він прийняв відповідь, виявляється, що йому потрібні лише модифікаційні ключі. Якщо вам потрібні інші клавіші, вам потрібно буде зателефонувати у GetKeyStateфункцію API.
СЛАкс

2
немає необхідності в GetKeyState. Вам просто потрібно додати фільтр повідомлень. Дивіться мою відповідь.
Ясен

2
Для рішення WPF ви можете скористатися Keyboard.Modifiers == ModifierKeys.Shift (для тих, хто прийшов сюди на пошуки)
Білл Тарбелл

3
замість (Control.ModifierKeys & Keys.Shift) != 0одного можна використовуватиControl.ModifierKeys.HasFlag(Keys.Shift)
tomuxmon

55

Код нижче - як виявити майже всі натиснуті в даний час клавіші, а не лише Shiftклавішу.

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
GetKeyStateбуло б ефективнішим. Немає сенсу відстежувати всі клавіші, коли Windows робить це вже для вас.
СЛАкс

3
@Slaks, якщо ви не маєте певних базових даних, ви здогадуєтесь. Більше того, GetKeyState повідомить вам про стан ключа, якщо ви зможете вловлювати цю подію на клавіатурі. Я читаю питання, що ОП хоче знати, як отримати стан ключа в будь-який час . Тож GetKeyState сам по собі марний.
Еш

3
Як саме ви використали це для показу натискання клавіш?
Габріель Райан Нахміас

Габріель: Створіть екземпляр KeyMessageFilter як поле у ​​формі. Передайте його Application.AddMessageFilter () у Form_Load. Тоді зателефонуйте IsKeyPress () у цьому випадку для кожної клавіші, яка вас зацікавила.
Еш,

@Аш дякую за вашу відповідь - чи зможете ви зробити приклад коду для перевірки клавіші SHIFT і т.д. вище?
BKSpurgeon

23

Ви також можете переглянути наступне, якщо ви посилаєтесь на System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

Простір імен клавіатури також можна використовувати для перевірки стану натискання інших клавіш за допомогою Keyboard.IsKeyDown (Key), або якщо ви підписуєтеся на KeyDownEvent або подібну подію, аргументи події містять список поточно натиснутих клавіш.


1
Насправді клавіатура. Модифікатори не завжди працюють належним чином. Довелося знайти важкий шлях: Discoveringdotnet.alexeyev.org/2008/09/…
Максим Алексєєв

За винятком випадків, коли не використовуються модифікатори Forms, модифікатори System.Windows.Input - це інший простір імен і кожен раз добре працює для нас.
Джефф Вайн

18

Більшість цих відповідей або занадто складні, або, здається, не працюють для мене (наприклад, System.Windows.Input, здається, не існує). Тоді я знайшов зразок коду, який працює добре: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

Якщо сторінка зникне в майбутньому, я розміщую відповідний вихідний код нижче:

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.Inputіснує; для інших, хто бореться з цим, вам потрібно додати посилання PresentationCoreта додаткове посилання WindowsBaseна доступ до System.Windows.Input.Keyперерахування. Цю інформацію завжди можна знайти на MSDN.
Алфі

1
Цей клас повинен бути static, ні abstract.
Little Endian

1
Ланка розірвана (404).
Пітер Мортенсен

2
"Якщо сторінка зникне в майбутньому, я розміщую відповідний вихідний код нижче"
persley72

12

Оскільки .NET Framework версії 3.0, Keyboard.IsKeyDownметод можна використовувати з нового System.Windows.Inputпростору імен. Наприклад:

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

Незважаючи на те, що він є частиною WPF, цей метод відмінно працює для програм WinForm (за умови, що ви додаєте посилання на PresentationCore.dll та WindowsBase.dll ). На жаль, однак версії Keyboard.IsKeyDownметоду 3.0 та 3.5 не працювали для додатків WinForm. Тому, якщо ви хочете використовувати його в додатку WinForm, вам потрібно буде орієнтуватися на .NET Framework 4.0 або пізнішої версії, щоб він працював.


лише зауважте, це лише для WPF
Дієго Віейра

2
@DiegoVieira Власне, це неправда. Функціональність додана як частина WPF, і вона вимагає посилання на ці бібліотеки WPF, але Keyboard.IsKeyDownметод працює навіть у проекті WinForm.
Стівен Доггарт

Дійсно, вам потрібно додати PresentationCore.dll
Diego Vieira

2
Зверніть увагу , це не працює (в WinForms) якщо вони націлені на .Net 3.5 або вище, тільки 4.0+, з - за змін в реалізації Win32KeyboardDevice.GetKeyStatesFromSystem (Key) :(
LMK

@LMK Хороший улов. Я сам це перевірив і перевірив те, що ви сказали. Я оновив свою відповідь, щоб відобразити цю інформацію. Дякую!
Стівен Доггарт

8

Ви можете P / Invoke вниз до Win32 GetAsyncKeyState, щоб перевірити будь-яку клавішу на клавіатурі.

Ви можете передати значення з перерахунку ключів (наприклад, Keys.Shift) до цієї функції, тому для її додавання потрібно лише пару рядків коду.


Keyboardне був розпізнаний компілятором, але GetAsyncKeystateв user32 працював просто чудово. Дякую!
Таємниця Ейнштейна X.

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

3

Найкращий спосіб мене керувати вводом клавіатури у формі Windows Forms - це обробити її після натискання клавіші і до того, як цілеспрямоване управління отримає подію. Microsoft підтримує вбудовану Formвластивість- level на ім'я .KeyPreview, щоб полегшити цю точну річ:

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

Тоді події _KeyDown, _KeyPress та / або _KeyUp форми можуть бути змінені для доступу до подій вводу до того, як цільовий контроль форми коли-небудь їх побачить, і ви можете застосувати логіку обробника, щоб захопити туди подію або дозволити їй перейти до сфокусованого контролю форми .

Незважаючи на структурну витонченість архітектури подій XAML , це робить управління функціями рівня форми в Winforms набагато простішим. Перегляньте нотатки MSDN на KeyPreview щодо застережень.


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

працює в текстовому полі, якщо вищевказаний код є подією клавіші форми, і жодне інше управління не фіксує події клавіші для клавіші.

Також можна зупинити подальшу обробку ключа за допомогою:

e.Handled = true;

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

Позиція курсору x / y є властивістю, а натискання клавіші (як натискання миші / переміщення миші) - це подія. Найкраща практика, як правило, дозволяють інтерфейсу керувати подіями. Про єдиний час, коли вам знадобиться вище, - це якщо ви намагаєтеся зробити заміну + клацання мишкою.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.