C# - 如何捕获Shift + Del组合事件而不捕获Shift键?

时间:2017-11-22 16:39:58

标签: c# winforms key keydown event-capturing

我有一个文本框和一个列表框。 Shift 必须清除列表框,并且 Shift + Del 组合必须清除文本框。

这是我的代码。

private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Shift && e.KeyCode == Keys.Delete) textBox.Clear();
    if (e.Shift) listBox.Items.Clear();
}

显然这是错误的,因为当 Shift 关闭时,列表框总是被清除。我需要能够通过按 Shift + Del 来清除文本框,并且当时不清除列表框。

我必须只使用 Shift Del 键而不使用其他键。

那我该怎么办?

2 个答案:

答案 0 :(得分:0)

首先,让我先说一下,我通常建议不要单独使用 Shift 键来触发除游戏之外的任何桌面软件中的动作。这样做会违反Principle of Least Astonishment:因为 Shift 在正常输入过程中经常使用以修改其他键的含义,因此用户有条件期望按下它不会执行任何后果本身,当然没有任何破坏性。因此,如果用户随意按下 Shift 并发现他刚刚丢失了他的物品清单,他可能会非常不愉快,特别是如果要解除这些伤害是困难或乏味的。

但是,你在评论中说你没有选择,所以说这是一个可能的解决方案。

为了能够区分 Shift Shift + Del 的组合,我们需要捕获 Dim frm as new master_ChartofAccount frm.showCoa() master_ChartofAccount个事件,并使用从每个事件收集的信息。

KeyDown事件中,我们会将KeyUp的值保存到私有字段,但尚未对其执行任何操作。 KeyDown包含组合的KeyEventArgs.KeyData标记,表示按下的主键,以及任何修饰键,如 Ctrl Shift Alt 同时被按下。请注意,当按下 Shift 时,它既是主键又是一个修饰符,因此KeyData将包含Keys(键)与KeyData(修饰语)结合。

Keys.ShiftKey

Keys.Shift事件中,我们会查看相对于上次按下的内容释放了哪些键。我们正在寻找两个特定的密钥序列:

    按下
  1. Shift + Del ,然后 Del 被释放,而 Shift 仍被按下。
  2. 按下
  3. Shift ,没有其他键,然后释放。
  4. 如果我们找到了我们正在寻找的东西,我们会采取适当的行动,否则我们什么都不做。

    private Keys LastKeysDown;
    
    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        LastKeysDown = e.KeyData;
    }
    

    请注意,作为最后一项业务,我们会清除私有KeyUp字段。这有助于确保如果我们连续获得两个private void MainForm_KeyUp(object sender, KeyEventArgs e) { // Shift + Delete pressed, then Delete released while Shift still held down if (LastKeysDown == (Keys.Shift | Keys.Delete) && e.KeyData == LastKeysDown) textBox1.Clear(); // Shift pressed with no other key, then released else if (LastKeysDown == (Keys.Shift | Keys.ShiftKey) && e.KeyData == Keys.ShiftKey) listBox1.Items.Clear(); LastKeysDown = Keys.None; } 个事件,则只有第一个事件与之前的LastKeysDown配对。但请注意,这并非万无一失:如果您按住一个键足够长的时间,计算机的重复键将会启动并生成其他KeyUp个事件。

答案 1 :(得分:-1)

如果您只想依赖Key_Down,您可以使用BackgroundWorker(或者Timer也会这样做)等待几毫秒才能清除列表。如果在此期间有另一个密钥进入,则取消后台工作程序。您的实现可能如下所示:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Shift && 
        e.KeyCode == Keys.Delete)
    {
        if (backgroundWorker1.IsBusy)
        {
            Trace.WriteLine("cancelling");
            backgroundWorker1.CancelAsync();
        }
        textBox.Clear();
    }

    if (e.Shift && 
        e.KeyCode == Keys.ShiftKey && 
        !backgroundWorker1.IsBusy)
    {
        backgroundWorker1.RunWorkerAsync();
    }

}

private void  backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = false;
    // wait 2 seconds (that is a bit long, adjust accordingly)
    Thread.Sleep(2000); // HACK, use a proper timer here
    // tell RunWorkerCompleted if we're good to clear
    e.Result = !backgroundWorker1.CancellationPending;
}

// this gets called on the UI thread
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Trace.WriteLine(String.Format("{0} - {1}", e.Cancelled, e.Result));
    if ((bool) e.Result)
    {
        listBox.Items.Clear();
    }
}

如果您还可以利用KeyUp事件,解决方案变得更加容易:

private bool onlyShift = false; // keeps shift state

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    // becomes true if this is the shift key pressed
    onlyShift = e.Shift && e.KeyCode == Keys.ShiftKey;

    if (e.Shift && 
        e.KeyCode == Keys.Delete)
    {
        textBox.Clear();
    }               
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
    // was the shiftkey the last one in keydown AND
    // are we releasing the shiftkey now
    if (onlyShift && e.KeyCode == Keys.ShiftKey)
    {
         listBox.Items.Clear();
    }
}

我个人会使用后一种解决方案。