【问题标题】:WPF: How to detect Key repetition, in Key* events?WPF:如何在 Key* 事件中检测 Key 重复?
【发布时间】:2010-12-23 07:22:07
【问题描述】:

注意e.IsRepeat 已确认有效。存在问题是因为我使用 从 Ubuntu 到 Windows 的远程桌面。

我找到了解决此远程桌面问题的方法:

  1. 在 Ubuntu 中禁用键重复。
  2. 在主机 Windows 中:使用“打开重复键和慢速键”启用筛选键
  3. 使用 regedit 转到 HKEY_CURRENT_USER\Control Panel\Accessibility\Keyboard Response
    1. AutoRepeatDelayAutoRepeatRate设置为足够小Last Valid DelayLast Valid Repeat
    2. 禁用 FilterKeys 并重新启用以刷新注册表更改。

如何检测KeyUp/KeyDown(或PreviewKeyDown/PreviewKeyUp)事件中的键重复?

我有以下测试用例:

    public Window1() {
        InitializeComponent();

        this.KeyDown += new KeyEventHandler(Window1_KeyDown);
        this.KeyUp += new KeyEventHandler(Window1_KeyUp);
    }

    void Window1_KeyUp(object sender, KeyEventArgs e) {
        if (e.Key == Key.D) {
            Console.WriteLine("DOWN: key: {0}, rep{1}, togg{2}, dow{3}, up{4}", e.Key, e.IsRepeat, e.IsToggled, e.IsDown, e.IsUp);
        }
    }

    void Window1_KeyDown(object sender, KeyEventArgs e) {
        if (e.Key == Key.D) {
            Console.WriteLine("UP: key: {0}, rep{1}, togg{2}, dow{3}, up{4}", e.Key, e.IsRepeat, e.IsToggled, e.IsDown, e.IsUp);
        }
    }

如果我按下字母 D 并在一段时间后释放它,它会给我 输出屏幕

// Note: Here I press D-key down.
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
UP: key: D, repFalse, toggTrue, dowTrue, upFalse
DOWN: key: D, repFalse, toggTrue, dowFalse, upTrue
UP: key: D, repFalse, toggFalse, dowTrue, upFalse
DOWN: key: D, repFalse, toggFalse, dowFalse, upTrue
// Note: Here I release D-key.

显然e.IsRepeat 总是假的,所以这是没用的。我也注意到,有时第一个事件也是toggFalse,dowTrue,所以不能用作模式。

我还注意到,使用计时的巧妙方法可用于检测重复,但必须有本地方法来执行此操作。

【问题讨论】:

  • 进一步观察:我注意到我无法重复您的实验。无论是使用文本框,是否写入控制台,是否在调试或发布中,无论是在 KeyDown 还是 PreviewKeyDown 中,它总是设置IsRepeat。您的代码是否有一部分未显示?
  • Abel,不,我为此创建了一个空项目。
  • 你说你在远程桌面上。你可以不试试吗?很可能,RD + Ubuntu 正在扮演你的角色。
  • 您找到了很好的解决方法!干得好(有趣的是,在 Ubuntu 中禁用它使其在 RD 中可用(尽管通过不同的方式)。

标签: c# .net wpf .net-3.5 keyboard-events


【解决方案1】:

为什么不使用本机的可能性?我在窗口和两个文本框上添加了一个 PreviewKeyDown 事件。在第二个文本框中按住一个键,这是输出:

Repeat: False, key: D
Repeat: True, key: D
Repeat: True, key: D
Repeat: True, key: D
Repeat: True, key: D
Repeat: True, key: D
Repeat: True, key: D
Repeat: True, key: D

这是我使用的代码:

private void Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
    textBox1.Text += String.Format(
        "Repeat: {0}, key: {1}\n", 
        e.IsRepeat, 
        e.Key);
}

更新: 删除了我的所有代码(其他测试中有一些垃圾)并按原样粘贴到您的代码中。它在控制台中给了我以下输出,所以我认为我们应该看看其他原因......

UP: key: D, repFalse, toggTrue, dowTrue, upFalse
UP: key: D, repTrue, toggTrue, dowTrue, upFalse
UP: key: D, repTrue, toggTrue, dowTrue, upFalse
UP: key: D, repTrue, toggTrue, dowTrue, upFalse
UP: key: D, repTrue, toggTrue, dowTrue, upFalse
UP: key: D, repTrue, toggTrue, dowTrue, upFalse

【讨论】:

  • 正确的事件是什么?正如我所说,如果我将事件更改为 Preview*,我的计算机上也无法设置 e.IsRepeat。
  • 注意到不同之处:无。我尝试了您尝试的方法(但仅在写完这篇文章之后)。我将 .NET 3.5 SP1 与普通的 WPF 项目一起使用。添加一个窗口,然后添加您的代码。
  • 刚刚在没有文本框的情况下进行了测试。作品。然后用你的代码测试。作品。嗯... .NET 不是最新的,您系统上的键盘记录器?
  • 我将不得不更深入地研究我的系统,如果能从人们那里获得更多关于此的结果会很好。我有 Windows 7 RC1 和 3.5SP1(我假设是 SP1,肯定是 3.5)...我通过 Ubuntu 的远程桌面连接。
  • 啊等等!远程桌面可能会在这里扮演你的角色!客户端系统(Ubuntu)必须通过 RD 客户端将关键事件发送到 Win7 服务器。尝试从控制台运行相同的代码(即坐在实际的计算机上),您可能会发现它再次运行。
【解决方案2】:

当 keydown 事件触发跟踪哪个键被按下时设置一个变量,做你的事情(tm)然后忽略该键的进一步事件。当 keyup 触发时清除变量。您可能需要一个列表来跟踪多个键。

【讨论】:

  • 嗯,对,看到 KeyUp 也被触发总是,所以它不会自然工作。
  • 但是,如果使用巧妙的计时方式,您所描述的方式会起作用,但这太疯狂了......正如我在问题中指出的那样,除了堆栈紧密计时的 keyUp/ 之外,必须有其他方法来检测键重复KeyDown 事件一起发生。
  • 不需要巧妙的计时,只需在正确的事件中使用IsRepeat,它就在那里。
  • 对不起,我对 WPF 还很陌生,所以如果你按住一个键,keyup 事件会触发吗?这似乎是个大问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多