จะตรวจจับคีย์ที่กดอยู่ในปัจจุบันได้อย่างไร?


124

ใน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 และอื่น ๆ
แอช

2
เนื่องจากเขายอมรับคำตอบดูเหมือนว่าเขาต้องการเพียงคีย์ตัวปรับแต่งเท่านั้น หากคุณต้องการคีย์อื่นคุณจะต้องเรียกใช้GetKeyStateฟังก์ชัน API
SLaks

2
ไม่จำเป็นต้อง GetKeyState คุณต้องเพิ่มตัวกรองข้อความ ดูคำตอบของฉัน
เถ้า

3
สำหรับโซลูชัน WPFคุณสามารถใช้ได้Keyboard.Modifiers == ModifierKeys.Shift (สำหรับผู้ที่มาที่นี่เพื่อค้นหา)
Bill 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 ด้วยตัวเองจึงไร้ประโยชน์
เถ้า

3
คุณจะใช้สิ่งนี้เพื่อแสดงปุ่มที่กดได้อย่างไร?
Gabriel Ryan Nahmias

Gabriel: สร้างอินสแตนซ์ของ KeyMessageFilter เป็นฟิลด์ในแบบฟอร์มของคุณ ส่งต่อไปยัง Application.AddMessageFilter () ใน Form_Load จากนั้นเรียก IsKeyPressed () บนอินสแตนซ์นี้สำหรับแต่ละ / คีย์ใด ๆ ที่คุณสนใจ
Ash

@Ash ขอบคุณสำหรับคำตอบของคุณ - คุณสามารถทำตัวอย่างโค้ดเพื่อตรวจสอบคีย์ SHIFT และอื่น ๆ ด้านบนได้หรือไม่?
BKSpurgeon

24

คุณยังสามารถดูสิ่งต่อไปนี้หากคุณใช้ WPF หรืออ้างอิง System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

นอกจากนี้ยังสามารถใช้เนมสเปซแป้นพิมพ์เพื่อตรวจสอบสถานะการกดของแป้นอื่น ๆ ด้วย Keyboard.IsKeyDown (คีย์) หรือหากคุณสมัครรับ KeyDownEvent หรือเหตุการณ์ที่คล้ายกันอาร์กิวเมนต์เหตุการณ์จะมีรายการของแป้นที่กดอยู่ในปัจจุบัน


1
คีย์บอร์ดจริงตัวปรับแต่งทำงานไม่ถูกต้องเสมอไป ต้องพบกับหนทางที่ยากลำบาก: Discoveringdotnet.alexeyev.org/2008/09/…
Maxim Alexeyev

ยกเว้นสิ่งนี้ไม่ได้ใช้ตัวปรับแต่ง Forms, System.Windows.Input modifiers เป็นเนมสเปซที่แตกต่างกันและทำงานได้ดีสำหรับเราทุกครั้ง
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
"ในกรณีที่หน้านี้หายไปในอนาคตฉันจะโพสต์ซอร์สโค้ดที่เกี่ยวข้องด้านล่าง"
ผักชีฝรั่ง 72

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 เท่านั้น
Diego Vieira

2
@DiegoVieira จริงไม่จริง ฟังก์ชันนี้ถูกเพิ่มเข้ามาเป็นส่วนหนึ่งของ WPF และจำเป็นต้องอ้างอิงไลบรารี WPF เหล่านั้น แต่Keyboard.IsKeyDownวิธีการนี้ใช้งานได้แม้ในโครงการ WinForm
Steven Doggart

แน่นอนคุณต้องเพิ่ม PresentationCore.dll
Diego Vieira

2
โปรดทราบว่าสิ่งนี้ใช้ไม่ได้ (ใน WinForms) หากกำหนดเป้าหมาย. Net 3.5 หรือเก่ากว่าเพียง 4.0+ เนื่องจากการเปลี่ยนแปลงในการใช้งาน Win32KeyboardDevice.GetKeyStatesFromSystem (คีย์) :(
LMK

@LMK ดีจับ. ฉันทดสอบด้วยตัวเองและตรวจสอบสิ่งที่คุณพูด ฉันอัปเดตคำตอบเพื่อแสดงข้อมูลดังกล่าว ขอบคุณ!
Steven Doggart

8

คุณสามารถP / Invokeลงไปที่ Win32 GetAsyncKeyStateเพื่อทดสอบคีย์ใด ๆ บนคีย์บอร์ด

คุณสามารถส่งผ่านค่าจาก Keys enum (เช่น Keys.Shift) ไปยังฟังก์ชันนี้ได้ดังนั้นจึงต้องใช้โค้ดสองสามบรรทัดในการเพิ่ม


Keyboardคอมไพเลอร์ไม่รู้จัก แต่GetAsyncKeystateใน user32 ทำงานได้ดี ขอบคุณ!
Einstein X. Mystery


3

วิธีที่ดีที่สุดที่ฉันพบในการจัดการการป้อนข้อมูลด้วยแป้นพิมพ์บนฟอร์ม Windows Forms คือการประมวลผลหลังจากการกดแป้นพิมพ์และก่อนที่ตัวควบคุมที่โฟกัสจะได้รับเหตุการณ์ Microsoft รักษาFormคุณสมบัติระดับในตัวที่ชื่อ. KeyPreviewเพื่ออำนวยความสะดวกในสิ่งที่แม่นยำนี้:

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

จากนั้นสามารถจัดกิจกรรม _KeyDown, _KeyPress และ / หรือ _KeyUp ของฟอร์มเพื่อเข้าถึงเหตุการณ์การป้อนข้อมูลก่อนที่ตัวควบคุมฟอร์มที่โฟกัสจะเห็นเหตุการณ์เหล่านี้และคุณสามารถใช้ตรรกะของตัวจัดการเพื่อจับเหตุการณ์ที่นั่นหรืออนุญาตให้ส่งผ่านไปยังตัวควบคุมฟอร์มที่เน้น .

แม้ว่าโครงสร้างจะไม่สง่างามเท่าสถาปัตยกรรมการกำหนดเส้นทางเหตุการณ์ของ XAMLแต่ก็ทำให้การจัดการฟังก์ชันระดับฟอร์มใน Winform นั้นง่ายกว่ามาก ดูหมายเหตุ MSDN ใน KeyPreviewสำหรับคำเตือน


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

ใช้งานได้กับกล่องข้อความหากโค้ดด้านบนอยู่ในเหตุการณ์คีย์ดาวน์ของแบบฟอร์มและไม่มีตัวควบคุมอื่นใดที่จับเหตุการณ์คีย์ดาวน์สำหรับคีย์ลง

นอกจากนี้คุณอาจต้องการหยุดการประมวลผลคีย์เพิ่มเติมด้วย:

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.