현재 누른 키를 감지하는 방법은 무엇입니까?


123

Windows Forms 에서는 Cursors 클래스 덕분에 언제든지 커서의 현재 위치를 알 수 있습니다 .

키보드에서도 동일한 기능을 사용할 수없는 것 같습니다. 예를 들어 Shift키를 눌렀 는지 알 수 있습니까?

모든 키보드 알림 (KeyDown 및 KeyUp 이벤트)을 추적해야합니까?


WPF 환경 또는 다른 환경에서 작업하고 있습니까?
epotter

70
@epotter : 두 번째 단어는 WinForms를 말합니다.
Will Eddins

답변:


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

Ctrl+ Shift가 다운 된 경우에도 마찬가지 입니다. Shift 만 눌 렸는지 확인하려면

if (Control.ModifierKeys == Keys.Shift)

상속하는 클래스 Control(예 : 양식)에있는 경우Control.


8
내가 빠진 게 아니라면 질문에 제대로 대답하지 않은 것입니다. OP는 모든 키에 대해 묻고 Shift 키를 예제로만 사용했습니다. 따라서 A에서 Z, 0에서 9 등과 같은 다른 키를 어떻게 감지합니까?
Ash

2
그가 대답을 받아 들였다는 점을 감안할 때 그는 수정 자 키만 필요한 것으로 보입니다. 다른 키를 원하면 GetKeyStateAPI 함수 를 호출해야 합니다.
SLaks

2
GetKeyState가 필요하지 않습니다. 메시지 필터 만 추가하면됩니다. 내 대답을 참조하십시오.
Ash

3
A에 대한 WPF 솔루션 당신은 사용할 수 있습니다 Keyboard.Modifiers == ModifierKeys.Shift (검색에 여기에 온 그 사람들을 위해)
빌 Tarbell

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가 이미 수행하는 경우 모든 키를 추적 할 필요가 없습니다.
SLaks

3
@Slaks, 벤치 마크 데이터가 없다면 추측하고 있습니다. 또한 GetKeyState는 처음에 해당 키보드 이벤트를 트랩 할 수있는 경우 키의 상태를 알려줍니다 . 질문에 대한 나의 독서는 OP가 언제든지 키의 상태를 얻는 방법을 알고 싶어한다는 것 입니다. 따라서 GetKeyState 자체는 쓸모가 없습니다.
Ash

3
눌려진 키를 표시하기 위해 이것을 정확히 어떻게 활용 하시겠습니까?
Gabriel Ryan Nahmias

Gabriel : 양식의 필드로 KeyMessageFilter 인스턴스를 작성하십시오. Form_Load의 Application.AddMessageFilter ()에 전달합니다. 그런 다음 관심있는 각각의 키에 대해이 인스턴스에서 IsKeyPressed ()를 호출합니다.
Ash

@Ash 귀하의 답변에 감사드립니다-위의 SHIFT 키 등을 확인하는 코드 예제를 수행 할 수 있습니까?
BKSpurgeon

24

System.Windows.Input을 참조하면 다음을 볼 수도 있습니다.

if (Keyboard.Modifiers == ModifierKeys.Shift)

Keyboard 네임 스페이스는 Keyboard.IsKeyDown (Key)을 사용하여 다른 키의 눌린 상태를 확인하는 데 사용할 수도 있습니다. 또는 KeyDownEvent 또는 유사한 이벤트를 구독하는 경우 이벤트 인수는 현재 눌린 키 목록을 전달합니다.


1
실제로 Keyboard.Modifiers가 항상 제대로 작동하는 것은 아닙니다. 하드 방법을 찾아야했다 : discoveringdotnet.alexeyev.org/2008/09/...
맥심 알렉 세 예프

이것이 Forms 수정자를 사용하지 않는 것을 제외하고 System.Windows.Input 수정자는 다른 네임 스페이스이며 매번 잘 작동했습니다.
Jeff Wain

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에서 찾을 수 있습니다.
Alfie

1
이 클래스는 있어야하는데 static, 없습니다 abstract.
Little Endian

1
링크가 끊어졌습니다 (404).
Peter Mortensen

2
"앞으로 페이지가 사라질 경우를 대비하여 아래에 관련 소스 코드를 게시하고 있습니다."
parsley72

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.dllWindowsBase.dll에 대한 참조를 추가하는 경우 ). 그러나 불행히도 3.0 및 3.5 버전의 Keyboard.IsKeyDown메서드는 WinForm 응용 프로그램에서 작동하지 않았습니다. 따라서 WinForm 응용 프로그램에서 사용하려면 .NET Framework 4.0 이상을 대상으로해야 작동 할 수 있습니다.


참고로, 이것은 WPF 전용입니다
Diego Vieira 2013

2
@DiegoVieira 사실, 그건 사실이 아닙니다. 이 기능은 WPF의 일부로 추가되었으며 해당 WPF 라이브러리를 참조해야하지만 Keyboard.IsKeyDown메서드는 WinForm 프로젝트에서도 작동합니다.
Steven Doggart 2013

실제로 PresentationCore.dll을 추가해야합니다
Diego Vieira 2013

2
Win32KeyboardDevice.GetKeyStatesFromSystem (Key)의 구현 변경으로 인해 .Net 3.5 또는 이전 버전을 대상으로하는 경우 (WinForms에서) 작동하지 않습니다 (WinForms에서) :(
LMK

@LMK 좋은 캐치. 나는 그것을 직접 테스트하고 당신이 말한 것을 확인했습니다. 해당 정보를 반영하기 위해 답변을 업데이트했습니다. 감사!
Steven Doggart 2014 년

8

당신은 할 수있는 P는 / 호출이 는 Win32까지 GetAsyncKeyState 키보드의 키를 테스트합니다.

Keys 열거 형 (예 : Keys.Shift)에서이 함수로 값을 전달할 수 있으므로 추가하는 데 몇 줄의 코드 만 필요합니다.


Keyboard컴파일러에서 인식되지 않았지만 GetAsyncKeystateuser32에서는 잘 작동했습니다. 감사!
Einstein X. Mystery

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

3

Windows Forms 양식에서 키보드 입력을 관리하는 가장 좋은 방법은 키 입력 후 포커스가있는 컨트롤이 이벤트를 받기 전에이를 처리하는 것입니다. Microsoft는 이 정확한 작업을 용이하게하기 위해 .KeyPreviewForm 라는 기본 제공 수준 속성을 유지합니다 .

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

그런 다음 폼의 _KeyDown, _KeyPress 및 / 또는 _KeyUp 이벤트를 마샬링하여 포커스가있는 폼 컨트롤이 입력 이벤트를보기 전에 입력 이벤트에 액세스 할 수 있으며 처리기 논리를 적용하여 이벤트를 캡처하거나 포커스가있는 폼 컨트롤을 통과 할 수 있습니다. .

XAML의 이벤트 라우팅 아키텍처 만큼 구조적으로 우아하지는 않지만 Winforms에서 양식 수준 함수를 훨씬 간단하게 관리 할 수 ​​있습니다. 주의 사항 은 KeyPreview에 대한 MSDN 노트를 참조하십시오 .


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

위 코드가 양식의 keydown 이벤트에 있고 다른 컨트롤이 keydown 이벤트를 캡처하지 않으면 텍스트 상자에 대해 작동합니다.

또한 다음을 사용하여 추가 키 처리를 중지 할 수 있습니다.

e.Handled = true;

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

커서 x / y 위치는 속성이고 키 누르기 (마우스 클릭 / 마우스 제거와 같은)는 이벤트입니다. 모범 사례는 일반적으로 인터페이스가 이벤트 기반이되도록하는 것입니다. 위의 내용이 필요한 유일한 경우는 shift + mouseclick 작업을 수행하려는 경우입니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.