【问题标题】:Stopping keys from repeating (C#)停止键重复(C#)
【发布时间】:2010-12-12 09:18:13
【问题描述】:

在这个应用程序中,我需要能够停止来自按下的键的响应,以防止不必要的数据进入输出。我遇到的问题是,使用下面代码中的方法确实可以防止按键重复,但也会阻止它们足够响应 - 因为用户非常快速地敲击按键。

我不确定这是我的硬件、api 限制还是我的代码有问题,但我下面的例程并不能简单地以足够快的速度运行而不会使程序无法使用。一种识别键是否被主动按下(以及持续多长时间)的方法也将有助于程序的另一个功能并解决当前的问题。

有什么想法吗?

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    e.SuppressKeyPress = isKeyDown;
    isKeyDown = true;
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
    isKeyDown = false;
}

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (!isStreamPlaying) return;
    if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
    {
        //red hit
        SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitnormal);
        hitSounds.Play();
        outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 0));
        lastms = ms;
    }
    else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
    {
        //blue hit
        SoundPlayer hitSounds = new SoundPlayer(taikoLiveMapper.Properties.Resources.normal_hitclap);
        hitSounds.Play();
        outputlist.Add(string.Format("320,240,{0},1,{1}", ms, 8));
        lastms = ms;
    }
}

【问题讨论】:

  • API 太慢了,无法完成我想要它做的事情。我不得不使用 DirectInput 处理所有这些代码,以便将它放在我想要的位置。

标签: c# winforms keypress keydown


【解决方案1】:

您可以使用 GetKeyState 找出某个键是否已按下并使用它来跟踪键:

    [DllImport("user32.dll")]
    static extern short GetKeyState(int key);

    static bool IsKeyPressed(Keys key)
    {
        short state = GetKeyState((int)key);
        return ((state & 128) != 0);
    }

    int i = 0;

    Dictionary<Keys, DateTime> downSince = new Dictionary<Keys, DateTime>();

    private void UpdateKeyStates()
    {
        foreach (var entry in downSince.ToArray())
        {
            if (!IsKeyPressed(entry.Key))
                downSince.Remove(entry.Key);
        }
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        UpdateKeyStates();
        if (!downSince.ContainsKey(e.KeyCode))
        {
            downSince.Add(e.KeyCode, DateTime.UtcNow);
            i++;

        }
        Text = i.ToString() + " " +(int)(DateTime.UtcNow - downSince[e.KeyCode]).TotalMilliseconds;
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        UpdateKeyStates();
    }

此示例在每次按下一个键时计数i,并显示它已按下多长时间。它使用 GetKeyState 而不是跟踪 KeyDown/KeyUp,因为如果其他内容有焦点,您可能会错过这些消息。

【讨论】:

  • 如果代码在 KeyDown 或 KeyPress 中,问题仍然存在。
  • 这似乎可以解决问题了。我不会逐字使用此代码,但我将使用 DirectInput 应用总体思路。谢谢!
【解决方案2】:

根据documentation,“如果按键被按住,则每次按键重复时都会发生 [d]uplicate KeyDown 事件,但当用户释放按键时只会生成一个 KeyUp 事件。”

所以最简单的解决方案是忽略重复的 KeyDown 事件,除非其对应的 KeyUp 事件已被看到。

刚刚为我工作。

【讨论】:

  • 那么为什么要投反对票?此解决方案对您不起作用吗?
  • 您的回答确实解决了这个问题,但它没有任何代码演示解决方案。这可能是投反对票的原因。
【解决方案3】:

改为使用计时器:初始化计时器,每个“动作”(例如按 d/j 或 s/k)在计时器内移动红色命中/蓝色命中代码,而不是您当前的代码,使用以下代码:

if (e.KeyChar.Equals('d') || e.KeyChar.Equals('j'))
{
    //red hit
    if (!tmrRedHit.Enabled)
        tmrRedHit.Enabled = true;
}
else if (e.KeyChar.Equals('s') || e.KeyChar.Equals('k'))
{
    //blue hit
    if (!tmrBlueHit.Enabled)
        tmrBlueHit.Enabled = true;
}

并且在代码执行后,计时器 Elpased 事件中也将它们的 Enabled 设置为 false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 2021-05-21
    • 2016-12-05
    • 1970-01-01
    相关资源
    最近更新 更多