阻止按键重复 (C#)

发布于 2024-10-07 15:49:31 字数 1177 浏览 9 评论 0原文

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

我不确定这是我的硬件、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;
    }
}

In this application, I need to be able to stop the response from a key which is held down in order to prevent unnessecary data from entering the output. The problem I'm having is, using the methods in my code below does prevent the keys from repeating, but it also stops them from being responsive enough - as the users are hitting the keys very quickly.

I'm not sure if it's my hardware, api restriction or a problem with my code, but the routines I have below do not simply come round fast enough to work without making the program impossible to use. A way of identifying if a key is being actively held down (and for how long) would also help another feature for the program and solve this current issue.

Any ideas?

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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

多彩岁月 2024-10-14 15:49:31

您可以使用 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,因为如果其他内容具有焦点,您可能会错过这些消息。

You can use GetKeyState to find out if a key is down and use that to track the keys:

    [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();
    }

This example counts i up every time a key is pressed, and shows for how long it has been pressed. It uses GetKeyState instead of tracking KeyDown/KeyUp since you might miss those messages if something else has focus.

风吹短裙飘 2024-10-14 15:49:31

根据文档< /a>, “如果按住该键,则每次重复该键时都会发生 [d]uplicate KeyDown 事件,但当用户释放该键时仅生成一个 KeyUp 事件。”

因此,最简单的解决方案是忽略重复的 KeyDown 事件,除非已看到其相应的 KeyUp 事件。

刚刚为我工作。

According to the documentation, "[d]uplicate KeyDown events occur each time the key repeats, if the key is held down, but only one KeyUp event is generated when the user releases the key."

So the simplest solution is to ignore a repeated KeyDown event unless its corresponding KeyUp event has been seen.

Just worked for me.

小清晰的声音 2024-10-14 15:49:31

使用计时器代替:初始化计时器,每个“操作”一个(例如按 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

Use Timers instead: initialize timers, one for each "action" (e.g. pressing d/j or s/k) move the red hit/blue hit code inside the timer and instead of your current code, have this:

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;
}

And in the timers Elpased event also set their Enabled to false after the code is executed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文